Patrick Desjardins Blog
Patrick Desjardins picture from a conference

Creating an Html Extension with the possibility to add Html Attribute with HtmlHelper.AnonymousObjectToHtmlAttributes

Posted on: 2012-07-04

When you are building a Html Extension, it's always a good idea to provide an overloaded of your extension that can have additional html attribute. This lead to the possibility to insert class, style or any other html attribute to the control that you are rendering.

First of all, you need to create the overload of your extension. You can also add at last parameter with default value with the default value to null because the type of this parameter should be object.

public static MvcHtmlString MyExtensionXZY<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, string anyThing) { 
  //... 
} 
public static MvcHtmlString MyExtensionXZY<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, string anyThing, object htmlAttributes) { 
  //... 
} 

Or this can be with a default value:

 public static MvcHtmlString MyExtensionXZY<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, string anyThing, object htmlAttributes=null) { 
  //... 
} 

In both case, the next step is to transform the object into a Dictionary. Why do we accept an object if it's to transform it into a Dictionary few lines after? The reason is to let anonymous object to be used. This way, it's possible to call the html helper without having to declare the dictionary every time we want to use it.

@Html.MyExtensionXZY("Test", new {class= "MyClass"}); 

Last step is to assign the attributes values to the html control that we are building. This can be done with a single line of code if you use a HtmlHelper method that is available in its static class.

myControl.MergeAttributes(System.Web.Mvc.HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes), true); 

So, what it does is that it takes the object html Attribute and convert it into a dictionnary. The method AnonymousObjectToHtmlAttributes is available in System.Web.Mvc.HtmlHelper:

public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes) { 
  RouteValueDictionary result = new RouteValueDictionary();

  if (htmlAttributes != null) {
    foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(htmlAttributes)) { 
      result.Add(property.Name.Replace('_', '-'), property.GetValue(htmlAttributes)); 
    } 
  }

  return result; 
} 

Once this is converted, it will be used with the MergeAttributes method of your new control. This method is available if you are using the System.Web.Nvc.TagBuilder class which let you create html tag. Once done with the TagBuilder, you only need to call the .ToString() of the object and you will get the generated html. As you may have notice, the MergeAttributes has "True" at its second parameter. This let know the builder that if an attribute was already available to override it with the new one. This let you have the final control of the rendering of your control.