Html attributes for EditorFor() in ASP.NET MVC

Htmlasp.net MvcEditorfor

Html Problem Overview


Why can't I pass in html attributes to EditorFor()? eg;

<%= Html.EditorFor(model => model.Control.PeriodType, 
    new { disabled = "disabled", readonly = "readonly" }) %>

I don't want to use metadata

Update: The solution was to call this from the view :

 <%=Html.EditorFor( model => model.Control.PeriodEndDate, new {Modifiable=model.Control.PeriodEndDateModifiable})%>

and use ViewData["Modifiable"] in my custom EditorTemplates/String.ascx where I have some view logic that determines whether to add readonly and/or disabled attributes to the input The anonymous object passed into EditorFor() is a parameter called additionalViewData and its properties are passed to the editor template in the ViewData collection.

Html Solutions


Solution 1 - Html

Update MVC 5.1 now supports the below approach directly, so it works for built in editor too. http://www.asp.net/mvc/overview/releases/mvc51-release-notes#new-features (It's either a case of Great mind thinking alike or they read my answer :)

End Update

If your using your own editor template or with MVC 5.1 which now supports the below approach directly for built in editors.

@Html.EditorFor(modelItem => item.YourProperty, 
  new { htmlAttributes = new { @class="verificationStatusSelect", style = "Width:50px"  } })

then in your template (not required for simple types in MVC 5.1)

@Html.TextBoxFor(m => m, ViewData["htmlAttributes"])

Solution 2 - Html

EditorFor works with metadata, so if you want to add html attributes you could always do it. Another option is to simply write a custom template and use TextBoxFor:

<%= Html.TextBoxFor(model => model.Control.PeriodType, 
    new { disabled = "disabled", @readonly = "readonly" }) %>    

Solution 3 - Html

As of MVC 5.1, you can now do the following:

@Html.EditorFor(model => model, new { htmlAttributes = new { @class = "form-control" }, })

http://www.asp.net/mvc/overview/releases/mvc51-release-notes#new-features

Solution 4 - Html

Now ASP.Net MVC 5.1 got a built in support for it.

From Release Notes

> We now allow passing in HTML attributes in EditorFor as an anonymous > object.

For example:

@Html.EditorFor(model => model, 
              new { htmlAttributes = new { @class = "form-control" }, })

Solution 5 - Html

Here is the VB.Net code syntax for html attributes in MVC 5.1 EditorFor

@Html.EditorFor(Function(x) x.myStringProp, New With {.htmlAttributes = New With {.class = "myCssClass", .maxlength="30"}}))

Solution 6 - Html

Why not just use

@Html.DisplayFor(model => model.Control.PeriodType)

Solution 7 - Html

If you don't want to use Metadata you can use a [UIHint("PeriodType")] attribute to decorate the property or if its a complex type you don't have to decorate anything. EditorFor will then look for a PeriodType.aspx or ascx file in the EditorTemplates folder and use that instead.

Solution 8 - Html

I've been wrestling with the same issue today for a checkbox that binds to a nullable bool, and since I can't change my model (not my code) I had to come up with a better way of handling this. It's a bit brute force, but it should work for 99% of cases I might encounter. You'd obviously have to do some manual population of valid attributes for each input type, but I think I've gotten all of them for checkbox.

In my Boolean.cshtml editor template:

@model bool?

@{
    var attribs = new Dictionary<string, object>();
    var validAttribs = new string[] {"style", "class", "checked", "@class",
        "classname","id", "required", "value", "disabled", "readonly", 
        "accesskey", "lang", "tabindex", "title", "onblur", "onfocus", 
        "onclick", "onchange", "ondblclick", "onmousedown", "onmousemove", 
        "onmouseout", "onmouseover", "onmouseup", "onselect"};
    foreach (var item in ViewData) 
    {
        if (item.Key.ToLower().IndexOf("data_") == 0 || item.Key.ToLower().IndexOf("aria_") == 0) 
        {
            attribs.Add(item.Key.Replace('_', '-'), item.Value);
        } 
        else 
        {
            if (validAttribs.Contains(item.Key.ToLower()))
            {
                attribs.Add(item.Key, item.Value);
            }
        }
    }
}

@Html.CheckBox("", Model.GetValueOrDefault(), attribs)

Solution 9 - Html

You can still use EditorFor. Just pass the style/whichever html attribute as ViewData.

@Html.EditorFor(model => model.YourProperty, new { style = "Width:50px" })

Because EditorFor uses templates to render, you could override the default template for your property and simply pass the style attribute as ViewData.

So your EditorTemplate would like the following:

@inherits System.Web.Mvc.WebViewPage<object>

@Html.TextBoxFor(m => m, new { @class = "text ui-widget-content", style=ViewData["style"] })

Solution 10 - Html

Html.TextBoxFor(model => model.Control.PeriodType, 
    new { @class="text-box single-line"})

you can use like this ; same output with Html.EditorFor ,and you can add your html attributes

Solution 11 - Html

Just create your own template for the type in Views/Shared/EditorTemplates/MyTypeEditor.vbhtml

@ModelType MyType

@ModelType MyType
@Code
    Dim name As String = ViewData("ControlId")
    If String.IsNullOrEmpty(name) Then
        name = "MyTypeEditor"
    End If
End Code

' Mark-up for MyType Editor
@Html.TextBox(name, Model, New With {.style = "width:65px;background-color:yellow"})

Invoke editor from your view with the model property:

@Html.EditorFor(Function(m) m.MyTypeProperty, "MyTypeEditor", New {.ControlId = "uniqueId"})

Pardon the VB syntax. That's just how we roll.

Solution 12 - Html

In my case I was trying to create an HTML5 number input editor template that could receive additional attributes. A neater approach would be to write your own HTML Helper, but since I already had my .ascx template, I went with this approach:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<input id="<%= Regex.Replace(ViewData.TemplateInfo.GetFullHtmlFieldId(""), @"[\[\]]", "_") %>" name="<%= ViewData.TemplateInfo.HtmlFieldPrefix %>" type="number" value="<%= ViewData.TemplateInfo.FormattedModelValue %>"
<% if (ViewData["attributes"] != null)
   {
       Dictionary<string, string> attributes = (Dictionary<string, string>)ViewData["attributes"];
       foreach (string attributeName in attributes.Keys){%>
        <%= String.Format(" {0}=\"{1}\"", attributeName, attributes[attributeName])%>
       <% }
   } %> />

This ugly bit creates a number type input and looks for a ViewData Dictionary with the key "attributes". It will iterate through the dictionary adding its key/value pairs as attributes. The Regex in the ID attribute is unrelated and is there because when used in a collection, GetFullHtmlFieldId() returns an id containing square brackets [] which it would normally escape as underscores.

This template is then called like this:

Html.EditorFor(m => m.Quantity, "NumberField", new { attributes = new Dictionary<string, string>() { { "class", "txtQuantity" } } }

Verbose, but it works. You could probably use reflection in the template to use property names as attribute names instead of using a dictionary.

Solution 13 - Html

Set the condition using ViewData in the controller

ViewData["Modifiable"] = model.recProcessed;

Then use this viewdata in editor template to set the html attribute of the control

@Html.RadioButton(prefix, li.Value, li.Selected, @ViewData["Modifiable"].ToString().ToLower() == "true" ? (object)new  { @id = li.Value, @disabled = "disabled" } : new { @id = li.Value })

Solution 14 - Html

MVC 5.1 and higher solution (will merge local HtmlAttributes and defined in the EditorTemplates):

Shared\EditorTemplates\String.cshtml:

@Html.TextBoxFor(model => model, new { @class = "form-control", placeholder = ViewData.ModelMetadata.Watermark }.ToExpando().MergeHtmlAttributes(ViewData["htmlAttributes"].ToExpando()))

Extensions:

public static IDictionary<string, object> MergeHtmlAttributes(this ExpandoObject source1, dynamic source2)
{
    Condition.Requires(source1, "source1").IsNotNull().IsLongerThan(0);

    IDictionary<string, object> result = source2 == null
        ? new Dictionary<string, object>()
        : (IDictionary<string, object>) source2;

    var dictionary1 = (IDictionary<string, object>) source1;

    string[] commonKeys = result.Keys.Where(dictionary1.ContainsKey).ToArray();
    foreach (var key in commonKeys)
    {
        result[key] = string.Format("{0} {1}", dictionary1[key], result[key]);
    }

    foreach (var item in dictionary1.Where(pair => !result.ContainsKey(pair.Key)))
    {
        result.Add(item);
    }

    return result;
}

public static ExpandoObject ToExpando(this object anonymousObject)
{
    IDictionary<string, object> anonymousDictionary = new RouteValueDictionary(anonymousObject);
    IDictionary<string, object> expando = new ExpandoObject();
    foreach (var item in anonymousDictionary)
        expando.Add(item);
    return (ExpandoObject)expando;
}

public static bool HasProperty(this ExpandoObject expando, string key)
{
    return ((IDictionary<string, object>)expando).ContainsKey(key);
}

Usage:

@Html.EditorFor(m => m.PromotionalCode, new { htmlAttributes = new { ng_model = "roomCtrl.searchRoomModel().promoCode" }})

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTypo JohnsonView Question on Stackoverflow
Solution 1 - HtmlAntonKView Answer on Stackoverflow
Solution 2 - HtmlDarin DimitrovView Answer on Stackoverflow
Solution 3 - HtmlvtforesterView Answer on Stackoverflow
Solution 4 - HtmlMurali MurugesanView Answer on Stackoverflow
Solution 5 - HtmlMaxView Answer on Stackoverflow
Solution 6 - HtmlMhoqueView Answer on Stackoverflow
Solution 7 - HtmlJohn FarrellView Answer on Stackoverflow
Solution 8 - HtmlIsochronousView Answer on Stackoverflow
Solution 9 - Htmluser394749View Answer on Stackoverflow
Solution 10 - HtmlzamoldarView Answer on Stackoverflow
Solution 11 - HtmlDarrel LeeView Answer on Stackoverflow
Solution 12 - Htmlxr280xrView Answer on Stackoverflow
Solution 13 - Htmlreine vargheseView Answer on Stackoverflow
Solution 14 - HtmlSerjGView Answer on Stackoverflow