MVC 3: Conditionally Adding the Disabled Attribute with the HtmlHelpers

If you want more terse syntax without requiring a helper function, you could use a ternary statement when defining the dictionary used for the html attributes of the @HTML.Checkbox helper...

@Html.CheckBox("CheckBox1", true, Model.ReadOnly 
       ? new { @class = "Class1", @disabled = Model.ReadOnly } 
       : null)

In this case is Model.ReadOnly is false, null gets passed as the dictionary of html attributes.


Define this somewhere in your view/helpers

@functions {
 object getHtmlAttributes (bool ReadOnly, string CssClass) 
 {
     if (ReadOnly) {
         return new { @class = CssClass, @readonly = "readonly" };
     }
     return new { @class = CssClass };
 }
}

Then use :

@Html.TextBox("name", "value", @getHtmlAttributes(Model.ReadOnly, "test"))

What do you think about my simple solution? It works easily with both possible HtmlAttributes types:

  • Dictionary<string, object>
  • Anonymous Object:

First add the following simple extension class to your project:

public static class HtmlAttributesExtensions
{
    public static IDictionary<string, object> AddHtmlAttrItem(this object obj, string name, object value, bool condition)
    {
        var items= !condition ? new RouteValueDictionary(obj) : new RouteValueDictionary(obj) {{name, value}};
        return UnderlineToDashInDictionaryKeys(items);
    }
    public static IDictionary<string, object> AddHtmlAttrItem(this IDictionary<string, object> dictSource, string name, object value, bool condition)
    {
        if (!condition)
            return dictSource;

        dictSource.Add(name, value);
        return UnderlineToDashInDictionaryKeys(dictSource);
    }
    private static IDictionary<string, object> UnderlineToDashInDictionaryKeys(IDictionary<string,object> items)
    {
        var newItems = new RouteValueDictionary();
        foreach (var item in items)
        {
            newItems.Add(item.Key.Replace("_", "-"), item.Value);
        }
        return newItems;
    }
}

Now in View:

Example1 (HtmlAttributes type as Anonymous Object)

@{
  var hasDisabled=true; 
}

@Html.CheckBox("CheckBox1"
              , true
              , new { @class = "Class1"}
               .AddHtmlAttrItem("disabled", "disabled", hasDisabled))
.

Example 2 (HtmlAttributes type as Dictionary<string, object>)

@Html.CheckBox("CheckBox1"
              , true
              , new Dictionary<string, object> { { "class", "Class1" }
               .AddHtmlAttrItem("disabled", "disabled", hasDisabled))
.

Now just change the hasDisabled value to true or false!


Example3 (Multiple conditional properties)

@{
  var hasDisabled=true;
  var hasMax=false ;
  var hasMin=true ;
}

@Html.CheckBox("CheckBox1"
              , true
              , new { @class = "Class1"}
               .AddHtmlAttrItem("disabled", "disabled", hasDisabled)
               .AddHtmlAttrItem("data-max", "100", hasMax)
               .AddHtmlAttrItem("data-min", "50", hasMin))
.

Here's my answer from this similar question: https://stackoverflow.com/a/13922813/495000


I created the following Helper - it takes a boolean and an anonymous object. If disabled is true, it adds the disabled attribute to the anonymous object (which is actually a Dictionary) with the value "disabled", otherwise it doesn't add the property at all.

public static RouteValueDictionary ConditionalDisable(
   bool disabled, 
   object htmlAttributes = null)
{
   var dictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

   if (disabled)
      dictionary.Add("disabled", "disabled");

   return dictionary;
}

An example of it in action:

@Html.TextBoxFor(m => m.SomeProperty,    
   HtmlHelpers.ConditionalDisable(true, new { @class = "someClass"))

One huge advantage to this approach for me was that it works with virtually all of the MVC HtmlHelpers since they all have Overloads that accept a RouteValueDictionary instead of an anonymous object.

Caveats:
HtmlHelper.AnonymousObjectToHtmlAttributes() uses some fancy code ninja work to get things done. I'm not entirely sure how performant it is... but it's been sufficient for what I use it for. Your mileage may vary.

I don't especially like the name of it - but I couldn't come up with anything better. Renaming is easy.

I also don't love the usage syntax - but again I couldn't come up with anything better. It shouldn't be difficult to change. An extension method on object is one idea... you'd end up with new { @class = "someClass" }.ConditionalDisable(true) but then if you only want the disable attribute and don't have anything additional to add you end up with something gross like new {}.ConditionalDisable(true); and you also end up with an extension method that shows up for all object... which is probably not desirable.