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 totrue
orfalse
!
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.