Reputation: 132
I am new to MVC3 and am still trying to pick up on the good programming practices. I had a heck of a time trying to format how a DateTime? was being displayed in my MVC3 project that doesn't have an explicit ModelName.cs file associated with the class the date was coming from.
We had a database already in place and use a .edmx (ours is called Pooling.edmx) that we get our models from. I obviously didn't want to edit the designer file to fit this widely accepted solution: Date only from TextBoxFor().
I then tried another solution which I found here: Using Html.TextBoxFor with class and custom property (MVC)
which uses:
@Html.TextBoxFor(m => m.Name, new { data_bind="value: Name", @class = "title width-7" })
This worked as I was able to use custom attributes, add class names, and set a Value all at once.
I transformed this:
@Html.TextBoxFor(m => Model.PrePoolOwner.OglDateEffective, new Dictionary<string, object> { { "class", "check-dirty input-small datePicker" }, { "data-original-value", @Model.PrePoolOwner.OglDateEffective } })
into this (which seems really ugly...and leads to me to the question):
@Html.TextBoxFor(m => Model.PrePoolOwner.OglDateEffective, new { data_original_value = Model.PrePoolOwner.OglDateEffective.HasValue ? Model.PrePoolOwner.OglDateEffective.Value.ToString("MM/dd/yyyy") : null, @class = "datePicker check-dirty", @Value = Model.PrePoolOwner.OglDateEffective.HasValue ? Model.PrePoolOwner.OglDateEffective.Value.ToString("MM/dd/yyyy") : null })
Is it better to find and use these other ways (like underscores will translate into dashes, etc) to display the information, or should I be having a ModelName.cs file to change how it is displayed at the Model level?
For some reason I feel having a huge Pooling.edmx file, that maps out our database, is limiting us now and will in the future on how we access/present/change data as the website evolves.
To get a "PrePoolOwner" object which is called up above by Model.PrePoolOwner.OglDateEffective, we have a PrePoolOwnerRow.cs file that does:
namespace OCC_Tracker.Models
{
public class PrePoolOwnerRow
{
public bool Dirty { get; set; }
public bool Delete { get; set; }
public PrePoolOwner PrePoolOwner { get; set; }
public PrePoolOwnerRow(PrePoolOwner owner)
{
this.Dirty = false;
this.Delete = false;
this.PrePoolOwner = owner;
}
public PrePoolOwnerRow()
{ }
}
}
We then call at the top of our .cshtml file
@model OCC_Tracker.Models.PrePoolOwnerRow
Upvotes: 3
Views: 2729
Reputation: 15513
Ok, so a few suggestions.
First, in your example, PrePoolOwnerRow
is your view model. This, in itself, is fine. But the code smell is where you expose PrePoolOwner
-- a domain entity -- through your view model, PrePoolOwnerRow
.
So first thing I would suggest is to update your view model to something more like this:
public class PrePoolOwnerModel
{
public bool Dirty { get; set; }
public bool Delete { get; set; }
public DateTime? OglDateEffective { get; set; }
public String OglDateEffective { get; set; }
// Other public properties here that map to properties on your PrePoolOwner entity.
}
All I did here was drop the reference to the domain model, and replace it with (a placehold comment to) the properties from your model, needed by your view.
In your controller, fetch your PrePoolOwner model, and map it to your view model using AutoMapper (this is a hypothetical example, as I don't know what your view is doing):
public ViewResult Index(int id)
{
PrePoolOwner entity = myservice.GetPrePoolOwner(id);
PrePoolOwnerModel model = Mapper.Map<PrePoolOwnerModel>(entity);
return View(model);
}
Now, to address the issue w/ the DateTime textbox, you should look at using MVC Editor Templates (this is another subject altogether, but Google it to find many topics covering the subject). This gives you more flexibility and re-usability over rendering elements of like types (i.e. DateTime).
But, aside from using that, you can add another property to your model, and use AutoMapper to set the DateTime appropriately. So, something like this in your controller, execpt you would set up a mapping in AutoMapper to handle this:
public class PrePoolOwnerModel
{
....
public String OglDateEffectiveValue { get; set; }
....
}
public ViewResult Index(int id)
{
....
model.OglDateEffectiveValue = model.OglDateEffective.HasValue ?
model.OglDateEffective.Value.ToString("MM/dd/yyyy") :
String.Empty;
....
}
Once that is set up, you can just use this new model property (OglDateEffectiveValue
) for your attributes on your textbox.
I know there's a lot I covered there, but dig in and experiment with modeling your view models like this, and using AutoMapper to map the data to your view model exactly like you need it to be on your view.
Keep your view logic very simple. Avoid using anything crazy beyond the occasion loop, and maybe an if conditional here or there.
Upvotes: 1