Stuart Leeks

Stuart Leeks - Application Development Consultant

ASP.NET MVC: Supplying HTML attributes with EditorFor

ASP.NET MVC: Supplying HTML attributes with EditorFor

  • Comments 5

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!

  • Nice.

  • 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 context

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

  • Hi, just thought I would let you know that using this technique, its easy (took me several hours of figuring a fundamental flaw in my knowledge of c# to figure out and play with the code, but hey...) to add html attributes in the razor syntax:

       public class HtmlAttributeProviders

       {

           public const string HtmlAttributesKey = "HtmlAttributes";

           public static Func<HtmlHelper, ModelMetadata, IEnumerable<KeyValuePair<string, object>>> HtmlAttributes = (html, metadata) =>

           {

               if (html.ViewData.ContainsKey(HtmlAttributesKey))

               {

                   return new RouteValueDictionary(html.ViewData[HtmlAttributesKey]);

               }

               return Enumerable.Empty<KeyValuePair<string, object>>();

           };

       }

    then add the following in global.asax.cs

               HtmlAttributeProvider.Register(HtmlAttributeProviders.HtmlAttributes);

    then in your views you can do something like:

       @html.Editor(property.Name, new {HtmlAttributes = new { disabled = "disabled" }})

    (You could wrap in an object to get rid of the typed "HtmlAttributes" in the above line, but I didn't need to add the time)

    Hope that this helps someone.

  • 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?

    2)  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).

Page 1 of 1 (5 items)
Leave a Comment
  • Please add 4 and 1 and type the answer here:
  • Post