amit_g
amit_g

Reputation: 31250

HTML 5 data attributes in HtmlHelper.xxxxxxFor overloads - object htmlAttributes / IDictionary<string, object> htmlAttributes

@Html.TextBoxFor(
    model => model.SomeProperty,
        new { data_url = "http://www.google.com" }
)

gets rendered as

<input id="SomeProperty" data-url="http://www.google.com">

I have some custom extensions similar to this

public static MvcHtmlString TextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes, bool disabled)
{
    var htmlAttrs = new RouteValueDictionary(htmlAttributes);

    return TextBoxFor<TModel, TProperty>(htmlHelper, expression, htmlAttrs, disabled);
}

public static MvcHtmlString TextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes, bool disabled)
{
    if (disabled)
    {
        htmlAttributes["disabled"] = true;
    }

    return htmlHelper.TextBoxFor(expression, htmlAttributes);
}

The first overload where object htmlAttributes is used htmlAttributes, invokes second overload where htmlAttributes gets converted to IDictionary<string, object> htmlAttributes and native TextBoxFor is invoked with IDictionary<string, object>. This means

@Html.TextBoxFor(
    model => model.SomeProperty,
        new { data_url = "http://www.google.com" }, model.IsSomePropertyDisabled
)

gets rendered as

<input id="SomeProperty" data_url="http://www.google.com">

Note data_url instead of data-url.

Essentially,

public static MvcHtmlString TextBox(this HtmlHelper htmlHelper, string name, object value, object htmlAttributes);

is smart enough to know that data_whatever is to be rendered as data-whatever, while

public static MvcHtmlString TextBox(this HtmlHelper htmlHelper, string name, object value, IDictionary<string, object> htmlAttributes);

doesn't seem to apply that logic (or we can say is not smart enough). Is there a way to tell it to apply the same logic?

As a workaround, I could opt to not use these overloads when I do need the data attributes and have verbose views when the disable attribute is to be applied. Any other way?

Upvotes: 1

Views: 2675

Answers (1)

archil
archil

Reputation: 39501

I think you need the HtmlHelper.AnonymousObjectToHtmlAttributes Method when creating htmlAttrs in first helper. Linked method

Replaces underscore characters (_) with hyphens (-) in the specified HTML attributes.

So, your first method should look like

public static MvcHtmlString TextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes, bool disabled)
{
    var htmlAttrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

    return TextBoxFor<TModel, TProperty>(htmlHelper, expression, htmlAttrs, disabled);
}

Upvotes: 7

Related Questions