1

I am trying to create a custom helper for EditorFor. I want to take the string lengths from the models and add this to the html attributes.

I have the following so far but this doesnt apply the new attributes that are added.

    public static IHtmlString MyEditorFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, object ViewData, bool disabled = false, bool visible = true)
    {
        var member = expression.Body as MemberExpression;
        var stringLength = member.Member.GetCustomAttributes(typeof(StringLengthAttribute), false).FirstOrDefault() as StringLengthAttribute;

        RouteValueDictionary viewData =  HtmlHelper.AnonymousObjectToHtmlAttributes(ViewData);
        RouteValueDictionary htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(viewData["htmlAttributes"]);

        if (stringLength != null)
        {
            htmlAttributes.Add("maxlength", stringLength.MaximumLength);
        }

        return htmlHelper.EditorFor(expression, ViewData);
    }
Stephan Bauer
  • 9,120
  • 5
  • 36
  • 58
user3208483
  • 385
  • 5
  • 14
  • `return htmlHelper.EditorFor(expression, ViewData)` is not adding any attributes. Its just using the original `ViewData` attribute you passed to the method –  Nov 16 '16 at 12:08
  • How can I edit that and return the attributes? I am unable to return the new viewData object as it is a different type – user3208483 Nov 16 '16 at 13:02

1 Answers1

1

You're returning original ViewData attribute in method parameter instead of custom HTML attributes collection on return htmlHelper.EditorFor(expression, ViewData). Based from this answer, your return method should changed to this:

public static IHtmlString MyEditorFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, object ViewData, bool disabled = false, bool visible = true)
{
    var member = expression.Body as MemberExpression;
    var stringLength = member.Member.GetCustomAttributes(typeof(StringLengthAttribute), false).FirstOrDefault() as StringLengthAttribute;

    RouteValueDictionary viewData =  HtmlHelper.AnonymousObjectToHtmlAttributes(ViewData);
    RouteValueDictionary htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(viewData["htmlAttributes"]);

    if (stringLength != null)
    {
        htmlAttributes.Add("maxlength", stringLength.MaximumLength);
    }

    return htmlHelper.EditorFor(expression, htmlAttributes); // use custom HTML attributes here
}

Then, apply custom HTML helper on view side like this:

@Html.MyEditorFor(model => model.Property, new { htmlAttributes = new { @maxlength = "10" }})

Edit:

This method works on MVC 5 (5.1) and above, I can't sure it works in earlier versions (refer this question: Html attributes for EditorFor() in ASP.NET MVC).

For earlier MVC versions, usage of HtmlHelper.TextBoxFor is more preferred, which certainly has maxlength attribute:

return htmlHelper.TextBoxFor(expression, htmlAttributes);

Additional references:

Set the class attribute to Html.EditorFor in ASP.NET MVC Razor View

HTML.EditorFor adding class not working

Community
  • 1
  • 1
Tetsuya Yamamoto
  • 24,297
  • 8
  • 39
  • 61
  • The `EditorFor()` method does not accept html attributes in its 2nd parameter –  Nov 17 '16 at 07:08