ASP.NET MVC: Supplying HTML attributes with EditorFor
My colleague Simon Ince and I recently discovered that we had been working on the same problem independently so we combined our efforts and have written a joint blog post on our team blog.
The problem was something that I’d encountered in a number of blog posts that used modified editor templates (jQuery UI datepicker, aria-required and autocomplete). In each of these posts I ended up adding a custom template, and then updating it to output an attribute in the rendered HTML. The thing that bothered me about all of these posts is that they didn’t compose well. For example, if you wanted to combine autocomplete and aria-required then you’d have to merge the changes to the templates. In the blog post, Simon and I walk through a fairly simple way to solve this problem with the introduction of HtmlAttributeProvider.
aria-required
In the remainder of this post I thought I’d show how the previous solutions would look with the new HtmlAttributeProvider. In the joint post we show how the aria-required scenario can be handled simply by adding the following line of code to global.asax:
HtmlAttributeProvider.Register(metadata =>metadata.IsRequired, "aria-required", true);
This simply says that when the model metadata has the IsRequired field set (e.g. if the property on the model has the Required attribute applied) then output an attribute with name “aria-required” and value “true”.
jQuery UI datepicker
In the case of the jQuery UI datepicker the approach is also simplified. In fact, we no longer need to create the Date.cshtml editor template. Instead we can simply add the following line of code to global.asax:
HtmlAttributeProvider.Register(metadata => metadata.DataTypeName == "Date", "class", "date");
This code says that if the DataTypeName is Date (e.g. if you’ve added the DataType(DataType.Date) attribute to the model property) then it should add the “date” class to the element. Note that the attribute provider handles merging attribute values, so this will add the “date” class to the other class values (i.e. it plays nicely with the classes that are added by default)
jQuery UI autocomplete
The autocomplete change requires a little bit more effort, but only a little! To trigger the autocomplete behaviour, we added a “data-autocomplete-url” attribute with the value of the URL that returns the autocomplete data. The generation of the URL uses HtmlHelper, so we need to use the overload of HtmlAttributeProvider.Register that allows us to pass a delegate that takes the HtmlHelper as a parameter:
HtmlAttributeProvider.Register((html, metadata) =>
{
string autocompleteUrl = html.GetAutoCompleteUrl(metadata);
if (!string.IsNullOrEmpty(autocompleteUrl))
{
return new[] { new KeyValuePair<string, object>(
"data-autocomplete-url", autocompleteUrl) };
}
return null;
});
The Register overload here expects a collection of attributes (KeyValuePairs) to be returned. The previous examples could have been written using this overload, but we opted to add a Register overload to simplify that common scenario.
Summary
Whilst it is nice that the previous scenarios have been simplified by the introduction of HtmlAttributeProvider, the real benefit is the composability as you can simply add multiple registrations!
Comments
Anonymous
September 03, 2012
Nice.Anonymous
October 14, 2012
HtmlAttributeProvider.Register(metadata => metadata.DataTypeName == "Date", "class", "date"); So where abouts to we put this in global.asax? I tried to put it in Application_Start but it tells me: Error 14 The name 'HtmlAttributeProvider' does not exist in the current contextAnonymous
January 12, 2013
Hi. You need install package "Install-Package UkadcHtmlAttributeProvider" with NuGet console and then in Global.asax.cs write "using UkAdcHtmlAttributeProvider.Infrastructure;" Then you can write "HtmlAttributeProvider.Register(metadata =>metadata.IsRequired, "aria-required", true);"Anonymous
March 15, 2013
The comment has been removedAnonymous
August 14, 2013
Hello! Thanks for this as it worked first time for me on my home pc, running Windows 7. But, running the same project on my work pc running under Windows XP, I get different behaviour. No datepicker! Unfortunately my work pc is not connected to the internet and is not the same configuration as my home pc. 1)Firstly, is there known problems running on XP?
- Is there some kind of utility that I can run that will show me the differences between my two machine builds? (XP & Windows 7) (Referring to all things Visual Studio).
- Anonymous
February 19, 2016
Turns out that MVC 5.1 gives us a new way to do this! Here's my explanation: 40north.wordpress.com/.../adding-attributes-to-html-editorfor-in-mvc-5-1