3

I know I can add html attributes to my tag by doing something like:

var htmlAttributes = new RouteValueDictionary { { "data-foo", "bar" } };
var tag = new TagBuilder("div");
tag.MergeAttributes(htmlAttributes );
@tag

Output:

<div data-foo="bar"></div>

I wonder if I can add attributes in a similar way by using markup instead of a tag builder. Maybe something like:

var htmlAttributes = new RouteValueDictionary { { "data-foo", "bar" } };
<div @htmlAttributes.ToHtmlAttributes() ></div>

Expected output:

<div data-foo="bar"></div>

Clearly, I wouldn't be able to handle merge conflicts this way. However, I think it's worth it because the second way is so much more readable.

Steven Wexler
  • 16,589
  • 8
  • 53
  • 80

1 Answers1

4

You can write your own extension method:

namespace SomeNamespace
{
    public static class RouteValueDictionaryExtensions
    {
        public static IHtmlString ToHtmlAttributes(this RouteValueDictionary dictionary)
        {
            var sb = new StringBuilder();
            foreach (var kvp in dictionary)
            {
                sb.Append(string.Format("{0}=\"{1}\" ", kvp.Key, kvp.Value));
            }
            return new HtmlString(sb.ToString());
        }
    }
}

which will be used exactly how you've described:

@using SomeNamespace    
@{
    var htmlAttributes = new RouteValueDictionary
        {
            {"data-foo", "bar"},
            {"data-bar", "foo"}
        };
}

<div @htmlAttributes.ToHtmlAttributes()> </div>

the result is:

<div data-foo="bar" data-bar="foo" > </div>

Edit:

If you want to use TagBuilder, you can alternatively write another extension which uses it internally:

public static IHtmlString Tag(this HtmlHelper helper, 
                              RouteValueDictionary dictionary, 
                              string tagName)
{
    var tag = new TagBuilder(tagName);
    tag.MergeAttributes(dictionary);
    return new HtmlString(tag.ToString());
}

and the usage shown below below gives the same output html as previously:

@Html.Tag(htmlAttributes, "div")
jwaliszko
  • 16,942
  • 22
  • 92
  • 158
  • This seems reasonable. However, I know `TagBuilder` must do something like this, so I thought that `System.Web` may expose a method that accomplishes this functionality. Do you know if one exists? – Steven Wexler Sep 04 '13 at 16:38
  • @steaks: I don't know if such out of the box extension method exists, but `TagBuilder` itself can be used in the way I've shown you in the edited section of my answer. – jwaliszko Sep 04 '13 at 18:45
  • I'm going with `ToHtmlAttributes`. However, I also, like your helper to create a tag. It's nice improvement to the IMO clunky TagBuilder API. One improvement I'd suggest is to include an extra parameter `Func innerHtml`. Use that parameter to set innerHtml `tag.InnerHtml = innerHtml(null).ToHtmlString();`. Also, you can accomplish the same functionality with a using block (which I like better). Have `Tag` return `IDisposable`. Then use `tag.ToString(TagRenderMode.StartTag)`, `tag.ToString(TagRenderMode.EndTag)`, and `System.Web.Mvc.ViewContext.Writer` appropriately. – Steven Wexler Sep 05 '13 at 16:33