Avoiding foreach for #html.checkboxfor - asp.net-mvc

I am developing an application using MVC. I had a requirement where I have to display checkbox for a list.
I was going through different posts for doing this, one of them is the use of avoiding foreach for looping and making use of #html.editorfor() as described in the answer by Darwin dimitrov here:
This answer works fabulously fine, but I have a clarification , it is:
In the same view I have 2 requirements , the one with checkboxfor and the other one with radiobuttonfor
So, If I am using
<div>#Html.EditorFor(x => x.RoleAccess)</div>
How do I write the (~/Views/Shared/EditorTemplates/RoleAccessViewModel.cshtml) to serve for checkboxfor for one requirement , and the other one for #radiobuttonfor .
Wont this approach be hardcoded which will always render the RoleAccessViewModel.cshtml whenever EditorFor(x => x.RoleAccess) is used?Please execuse me If I have used any technical terms wrong way,as I still a novice in mvc.

The EditorFor method has an overload that accepts a template name as argument. I think that solves your problem if I understand it correctly. See http://msdn.microsoft.com/en-us/library/ee407414%28v=vs.118%29.aspx

You can also solve this by using the UIHint attribute on your property instead (or in addition to) relying on naming the template after your view model. Then you can create an alternate template to render the radio buttons and specify that:
[UIHint("RadioList")]
public List<Something> MyRadioButtonList { get; set; }
EditorFor will then look for the template: Views\Shared\EditorTemplates\RadioList.cshtml
You could do the same for your checkbox list, as well, instead of relying on the view model. For example, [UIHint("CheckboxList")] and CheckboxList.cshtml. Then, you'd be able to apply these templates more broadly.

Related

Custom UIHint attribute

Is it possible to create a custom version of the UIHint attribute?
When my company first adopted MVC, we used a lot of Html.* helper methods. We are in the process of redesigning out MVC template to make use of the full power of MVC. One way we are doing this is with Display and Editor Templates.
However, one popular HTML extension method we had was to generate dropdowns for Enums. One of the options we had was to sort by the int value or the description or text of the EnumMember.
I would like to see about creating a EnumDropdown attribute that accepts several parameters that can customize the output of the HTML dropdown. However, I don't think it's possible to do this while still retaining the benefits of the UIHint attribute. Meaning, that I won't be able to simply call #Html.EditorFor(m => Model)
I had found that there is a System.Web.UI.IAutoFieldGenerator interface but it doesn't appear to do what I want. Any suggestions?
The newer versions of MVC have this built in now:
EnumDropDownListFor HTML Helper
The only thing UIHint does is suggest a Display or Editor template name. MVC will then add this name to the search path when looking for that template.
You can just use UIHint as is and have your generator create these for you in the correct folders and not have to customize it.

Where is the best place to format Model properties in ASP.NET MVC(3)?

I've been looking a lot recently as best practices within the ASP.NET MVC framework, specifically around sparation of concern. My question here is, if I have a property on a model, where is the best place to do some formatting on that property?
I've thought about a few options but am not sure which is best. The example uses a DateTime. Sorry this got a bit long.
Option 1:
In the view: #Model.TheDate.String("{0:'blah'dd/MM/yyyy}")
I know this isn't right because the format string shouldn't be here (what if I want to change the format throughout the whole app)
Option 2:
Extension method used within the view: #Model.TheDate.DisplayItNicePlease()
This kind of makes sense because the view is chosing the extension method to use for formatting and the viewmodel just exposes the date property to the view. Not sure if the view or view model should be responsible for formatting though.
Option 3:
In an Html Helper method, i.e. something like Where should I place Declarative HTML helpers in ASP.NET MVC 3 so you could use:
#Html.DisplayDateNice(Model.TheDate)
Option 4:
Extra property on the view model to format it and return a string e.g.:
public string TheDateStr
{
get
{
return TheDate.DisplayItNicePlease();
}
}
And then in the view you just have
#Model.TheDateStr
Fairly similar to option 3 only it keeps the view really, really simple - the view literally just outputs what is in the model and doesn't care about the format of the data.
Option 5:
DisplayFormat attributes, e.g.:
On the view model:
[DisplayFormat(DataFormatString = "{0:'blah'dd/MM/yyyy}")]
public DateTime TheDate { get; set; }
And then on the view:
#Html.DisplayFor(m => m.TheDate)
I like this apart from again the format string is not reused, so bring on option 5...
Option 6:
Some kind of custom DisplayFormatAttribute e.g. NiceDateDisplayFormatAttribute.
This seems to me like it might be the nicest solution and works well if you just want a simple string formatting. I think this gets more complicated if you want something more complicated, e.g showing relative time (Calculate relative time in C#), in which case maybe this is best being in an extension method/html helper.
There are probably other ways I'm not even aware of...
Either use an extension helper to format the type if this type formatting will be used a lot or add an extra property in the Model to return a formatted version of the original property.
For a single view, I personally use option 5: putting it in the view model.
If date format's being used for multiple pages, you can create a html helper extension for formatting the date. So in the view, you'd have something like
#Model.TheDate.ToDateString()
But overall, i still prefer option5 because i create viewmodels for everypage, and just throw a DisplayFormat attribute on it.

EditorTemplates/Object.cshtml using EditorFor() instead of Editor()?

I am trying to create a generic editor template that replicates Html.EditorForModel(), to later customize and build upon. Brad Wilson's template gets pretty close, but I found that it chokes when the same key exist in both ViewData (or ViewBag) and the model. For example ViewBag.Title causes problems if the view model also has a Title property.
I learned here that using strongly-type helpers (i.e. Html.EditorFor(x => x.Title) instead of Html.Editor("Title") seems to help. So I tried to modify Brad's template, but I ran into a brick wall, as nothing I tried so far has worked. I can't figure out how to use strongly-typed helpers in a context where I don't know the model type, like an editor template for example.
Is there any way to create an Object template like Brad's, but using strongly-typed helpers (i.e. LabelFor, EditorFor, ValidatorMessageFor) instead of weakly-typed ones (i.e. Label, Editor, ValidatorMessage)?
Thanks.
I solved this problem in a slightly roundabout way, by removing the ViewData right before the call to #Html.Editor and then putting it back after.
Object.cshtml:
object oldViewData = null;
var hasConflictingViewData = ViewData.TryGetValue(prop.PropertyName, out oldViewData);
if (hasConflictingViewData)
{
ViewData.Remove(prop.PropertyName);
}
#Html.Editor(prop.PropertyName)
if (hasConflictingViewData)
{
ViewData.Add(prop.PropertyName, oldViewData);
}
The only other option I could think of is using a ton of reflection to call EditorFor generically with a runtime type, and pass in an expression for the pertinent property.
You can view all of the code for the new Object.shtml by going and downloading the MVC source code. I thought it was also in some common folder on your pc already but I can't remember where.
http://aspnet.codeplex.com/releases/view/58781

ASP.NET MVC / Linq-to-SQL classes: Can I get it to infer readable display names?

If I have a table Orders with fields CustomerID, OrderID and OrderDate, then the "Linq-to-SQL classes" generated class will be called Orders, with members called CustomerID, OrderID and OrderDate. So far so good.
However, if I then do Html.LabelFor(m => m.OrderDate) then the generated text will be "OrderDate" instead of "Order Date".
I tried using Order_Date as the field name, but that didn't work. Is there any way to get it to infer a better display name?
[I know that I can use data annotations to specify the display name explicitly, but I really don't want to do that for all my classes/members - I just want it to work by convention.]
I suggest you create your own HTML Helper for this, something like Html.MyLabelFor.
The rules to apply from here are up to you. You can simply split the word by case.
There is a solution available for your requirements contained within the answer to this question. Asp.Net MVC 2 LabelFor Custom Text.
This method takes advantage of existing MVC 2 architecture to place conventions over the entire *For rendering methods instead of one off HTML helpers and without having to re-label everything with spaced property names.
How to "DRY up" C# attributes in Models and ViewModels?
Essentially what your doing is overriding the default ConventionModelMetadataProvider behavior of MVC 2 and providing hooks for you to insert your own opinionated conventions.

Passing model data to asp.net mvc EditorTemplates

ScottGu in this post link text shows how one can utilize EditorTemplates for things such as a Country DropDownList. My question is how can one pass a dynamic list of Countries to the EditorTemplate?
Even better you make the partial view strongly typed and pass the model to the EditorFor helper
#Html.EditorFor(m=>m.SelectedCountry, Model.AvailableCountries)
Probably the most elegant solution is using a Custom Attribute, you can later access Model metadata using: ViewData.ModelMetadata.
e.g:
[Foreign(Type="DropDown", TableName="Countries")]
public int IdCountry { get; set; }
where ForeignAttribute is a class you must declare, and later use it to build your editor template.
You can pass it in ViewData and feed ViewData from and ActionFilter if the data is required very often (although arguable it is an anti-pattern).
Similar to #Benja's answer
You can also use the [AdditionaMetaData(key,value)] attribute in a similar fashion without having to define your own attribute. Key and value have to be strings.
The extra data can be retrieved in the view with: #ViewData.ModelMetadata.AdditionalValues["DropDownData"]

Resources