Search code examples
c#asp.net-mvchtml-helpermvchtmlstring

TagBuilder.MergeAttributes does not work as expected


I am trying to make a HtmlHelper and I need to allow users to add their own custom attributes to the html tag.

I tried to do this using the TagBuilder class, but it seems that instead of merging the attributes, it just replaces them.

This is what I did in C#:

public static MvcHtmlString List(HtmlHelper helper, object htmlAttributes)
{
    var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

    var tag = new TagBuilder("div");
    tag.AddCssClass("myClass");
    tag.MergeAttributes(attributes, false);

    // tag class property has value "myClass", not "myClass testClass"

    return new MvcHtmlString("<div>");
}

This is my view:

@Html.List(new { @class = "testClass" })

What am I doing wrong?


Solution

  • The TagBuilder.MergeAttributes method doesn't work how you expect it to. This is the exact code of this method:

        public void MergeAttributes<TKey, TValue>(IDictionary<TKey, TValue> attributes, bool replaceExisting)
        {
            if (attributes != null)
            {
                foreach (var entry in attributes)
                {
                    string key = Convert.ToString(entry.Key, CultureInfo.InvariantCulture);
                    string value = Convert.ToString(entry.Value, CultureInfo.InvariantCulture);
                    MergeAttribute(key, value, replaceExisting);
                }
            }
        }
    
        public void MergeAttribute(string key, string value, bool replaceExisting)
        {
            if (String.IsNullOrEmpty(key))
            {
                throw new ArgumentException(CommonResources.Argument_Cannot_Be_Null_Or_Empty, "key");
            }
    
            if (replaceExisting || !Attributes.ContainsKey(key))
            {
                Attributes[key] = value;
            }
        }
    

    As you can see it only adds new attributes to the collection (if replaceExisting is set to true it also replaces the ones already in the collection). It doesn't perform and attributes values merging logic. If you want to merge values you need to do it by yourself:

    public static MvcHtmlString List(this HtmlHelperhelper, object htmlAttributes)
    {
        var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);        
        if (attributes.ContainsKey("class"))
            attributes["class"] = "myclass " + attributes["class"];
        else
            attributes.Add("class", "myClass");
    
        var tag = new TagBuilder("div");
        tag.MergeAttributes(attributes, false);
    
        return new MvcHtmlString(tag.ToString(TagRenderMode.Normal));
    }