MVC 3: conditionally adding a disabled attribute using HtmlHelpers

I have an ASP.Net MVC 3 web application and I add a checkbox to the view page using the HtmlHelper class, for example ...

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

What I want to do is to conditionally add a disabled attribute based on the view property. Basically, it would be perfect ...

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

Unfortunately, due to the nature of the disabled attribute, this will not work, because any value assigned to the disabled attribute (even "false") will be translated as true.

I already thought of several solutions to get around this problem, so the question is not how I can do this. But rather, is there a simple way, like the desired method above? or do I need to resort to one of the following? ..

What I know, I could do ...

  • Create an if / else statement and write in different lines Html.CheckBox (not very readable), and it is possible to reset the markup warning - not sure)

  • Skip the HtmlHelper class and manually write a tag to improve conditional attributes (shortens the code, but adds inconsistency)

  • Create a custom helper that accepts the "disabled" option (the cleanest solution, but requires unwanted additional methods - perhaps the best option so far)

+58
asp.net-mvc asp.net-mvc-3 html-helper
Nov 02 2018-11-11T00
source share
6 answers

Define it 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")) 
+46
Nov 02 2018-11-11T00:
source share

Here is my answer from this similar question: stack overflow




I created the following Helper - it accepts a logical and anonymous object. If the value is disabled, it adds the disabled attribute to the anonymous object (which is actually a Dictionary) with the value "disabled", otherwise it does not 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 this in action:

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

The huge advantage of this approach for me was that it works with almost all MVC HtmlHelpers, since they all have Overloads that accept RouteValueDictionary instead of an anonymous object.

Caution :
HtmlHelper.AnonymousObjectToHtmlAttributes() uses some ninja work for trendy code to get things done. I'm not quite sure how effective it is ... but that was enough for what I use it for. Your mileage may vary.

I do not like this name, but I could not think of anything better. Renaming is easy.

I also do not like the syntax of use, but again I could not think of anything better. It should not be difficult to change. The extension method on the object is one idea ... you end up with new { @class = "someClass" }.ConditionalDisable(true) , but if you only need the disable attribute and you have nothing more to add to something like rough like new {}.ConditionalDisable(true); , and you also end with an extension method that is displayed for all object ... which is probably undesirable.

+26
Dec 17 '12 at 22:05
source share

If you need more complex syntax that does not require an auxiliary function, you can use the three-dimensional operator when defining the dictionary used for the html @ HTML attributes. Checkbox helper ...

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

In this case, Model.ReadOnly is false, null is passed as the html attribute dictionary.

+9
Jun 25 '13 at 16:11
source share

Doing the addition of a disabled client attribute part works for me. Note that you should check which fields are allowed for editing on the server side, but this is true for where the disabled attribute is also declared decoratively.

In this example, I disabled all form elements using jQuery.

  if (Model.CanEdit) { <script type="text/javascript"> $(document).ready(function() { $('#editForm *').attr('disabled', true); }); </script> } 
+1
Jul 05 '13 at 14:13
source share
 @Html.TextBoxFor(m => m.FieldName, Html.FixBoolAttributes(new { @class = "myClass", @readonly = myFlag })) public static class BooleanAttributeFix { /// <summary> /// Normalises HTML boolean attributes so that readonly=true becomes readonly="readonly" and /// readonly=false removes the attribute completely. /// </summary> /// <param name="htmlHelper"></param> /// <param name="htmlAttributes"></param> /// <returns></returns> public static RouteValueDictionary FixBoolAttributes(this HtmlHelper htmlHelper, object htmlAttributes) { var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes); foreach(var attrName in new[] { "disabled", "readonly" }) { object value; if(attrs.TryGetValue(attrName, out value)) { if(isTruthy(value)) { // Change from readonly="true" to readonly="readonly" attrs[attrName] = attrName; } else { // Remove attribute entirely attrs.Remove(attrName); } } } return attrs; } /// <summary> /// Apply similar loose rules like javascript does for whether a value is true or not. /// eg 1 = true, non-empty string = true and so on. /// </summary> /// <param name="val"></param> /// <returns></returns> private static bool isTruthy(object val) { if(val == null) return false; if(val is string) { return !String.IsNullOrEmpty((string)val); } Type t = val.GetType(); if(t.IsValueType && Nullable.GetUnderlyingType(t) == null) { // If a non-nullable value type such as int we want to check for the // default value eg 0. object defaultValue = Activator.CreateInstance(t); // Use .Equals to compare the values rather than == as we want to compare // the values rather than the boxing objects. // See http://stackoverflow.com/questions/6205029/comparing-boxed-value-types return !val.Equals(defaultValue); } return true; } } 
+1
Sep 09 '15 at 14:43
source share

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

  • 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 mode:

Example1 ( HtmlAttributes enter 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 value of makeItReadOnly to true to false !




Example 3 (Several 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)) . 
0
Sep 08 '16 at 16:56
source share



All Articles