Search code examples
c#razortagbuilder

RouteValueDictionary to HtmlAttributes


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.


Solution

  • 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")