Question

If I am passing HtmlAttributes into a template, like this:

@Html.DisplayFor(m => m.FirstName, new { htmlAttributes = new { @class = "orangetxt strongtxt" } })

In my template, how would I inject these into my HTML:

<span @ViewData["htmlAttributes"]>@Model</span>

This almost works, but it does some pretty weird stuff, so I'm assuming this isn't the way to go.

I realize I can accomplish this with an HtmlHelper extension method to render the full HTML element (span, in this case) and pass in the attributes that way, but is there a way to just render attributes straight into an HTML element, like the above example?

Was it helpful?

Solution

The below extension method will allow me to convert HtmlAttributes to a string:

    public static MvcHtmlString RenderHtmlAttributes<TModel>(
        this HtmlHelper<TModel> htmlHelper, object htmlAttributes)
    {
        var attrbituesDictionary = new RouteValueDictionary(htmlAttributes);

        return MvcHtmlString.Create(String.Join(" ", 
            attrbituesDictionary.Select(
                item => String.Format("{0}=\"{1}\"", item.Key, 
                htmlHelper.Encode(item.Value)))));
    }

Then, to render them within the tag, I can just do this:

<span @Html.RenderHtmlAttributes(ViewData["htmlAttributes"])>@Model</span>

OTHER TIPS

Jerad Rose's answer is good, but I ran into couple of issues with it:

  • It does not not convert underscores to dashes in attribute names
  • It does not handle no-value attributes gracefully

To address first issue, use HtmlHelper.AnonymousObjectToHtmlAttributes.

Below is my modification of Jerad's method:

public static MvcHtmlString RenderHtmlAttributes(this HtmlHelper helper, object htmlAttributes)
{
        if (htmlAttributes == null) return new MvcHtmlString(String.Empty);
        var attrbituesDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
        return new MvcHtmlString(String.Join(" ", attrbituesDictionary.Select(item => string.IsNullOrEmpty((string)item.Value) ? String.Format("{0}", item.Key) : String.Format("{0}=\"{1}\"", item.Key, helper.Encode(item.Value)))));
}

Try this instead,

@Html.DisplayFor(m => m.FirstName, 
                 new { htmlAttributes = "class = orangetxt strongtxt"})

This will render a string, whereas your version did do weird stuff, rendered { } as part of the output.

DisplayFor() is used to render the template that matches the property type.

Display templates are .cshtml files inside /DisplayTemplates folder which in turn is inside a view folder (i.e. any folder from Home, Shared or even a specific controller).

An example.

If you've a String.cshtml template like this inside /Views/Shared:

@model String

@if (string.IsNullOrEmpty(Model)) {
   <span>(no string)</span>
}
else {
   <span>@Model</span>
}

Every time you call DisplayFor() for a string property:

DisplayFor(model => model.MyStringProperty);

It renders the template accordingly to the string's value. You can be more specific and put /DisplayTemplates inside a specific View folder and them only calls from those views are affected by the template.


In your case you can be even more specific and call DisplayFor() with a particular template.

Suppose you've a template for a particular property, called MyPropertyTemplate.cshtml. You would call DisplayFor() like this:

DisplayFor(model => model.MyProperty, "MyPropertyTemplate");

And them, inside that template you can have whatever HTML attributes you want.

@model MyProperty

<span class="orangetxt strongtxt">@MyProperty.ToString()</span>

PS: When it doesn't find a template I guess it only calls model.Property.ToString() without additional html.

FYI: EditorFor(), for example, works in a similar way but it uses /EditorTemplates folder.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top