Adding HtmlAttributes to template
Asked Answered
T

4

10

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?

Turnspit answered 19/10, 2011 at 23:57 Comment(0)
T
9

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>
Turnspit answered 20/10, 2011 at 14:1 Comment(1)
Hmm i may be wrong here, but your intended usage as based on the question, seems to me will not work..can you perhaps include how you are using the helperWhyalla
V
5

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)))));
}
Vigorous answered 14/8, 2014 at 16:44 Comment(0)
W
1

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.

Whyalla answered 20/10, 2011 at 6:57 Comment(4)
This is close, but still not exactly what I'm looking for. I don't really want to have to deal with all of the string conversion and encoding. I actually came up with an extension method to render HTML attributes, and will post that below.Turnspit
@JeradRose - based on what you have current, nothing changes except the actual call to Displayfor so no conversions and encodingWhyalla
Yes, but the above was just an example. I may have cases where the attributes need to be a bit more complex, and will require quotes. For example, if I need to include class = "orangetxt strongtxt" id = "myId", then it starts to get a little crazy using your solution.Turnspit
@JeradRose - fair enough, I didn't catch the part about using multiple attributes, my bad...Whyalla
P
0

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.

Parasynthesis answered 20/10, 2011 at 1:9 Comment(3)
Thanks. I understand how templates work, I just need to figure out how to pass in HtmlAttributes to a template and render them like in the example above, without hard-coding these in a new template. I want them to be more flexible.Turnspit
The problem with templates, Jerad, is where do the htmlAttributes go? You could have a huge template with many divs and what not. What you want to do will be very custom and it basically involves writing your own HtmlHelper methods to output with the custom htmlAttributes.Ursala
True, I understand that with complex templates, it's hard to know what the htmlAttributes would get applied to. In my case, it will always be applied to the element immediately surrounding the model value. If I wanted to, say, include another option to apply custom attributes to the label, then I could add support for labelHtmlAttributes, for example.Turnspit

© 2022 - 2024 — McMap. All rights reserved.