Ollie
Ollie

Reputation: 885

How to set disabled in MVC htmlAttribute

When using an HTML Helper, what is the best method to set an attribute based on a condition. For example

<%if (Page.User.IsInRole("administrator")) {%>
<%=Html.TextBoxFor(m => m.FirstName, new {@class='contactDetails'}%>
<%} else {%>
<%=Html.TextBoxFor(m => m.FirstName, new {@class='contactDetails', disabled = true}%>
<%}%>

There must be a better way to programmatically add just one additional KeyPair to the anonymous type? Can't use

new { .... disabled = Page.User.IsInRole("administrator") ... }

as the browser takes any disabled attribute value as making the input disabled

Upvotes: 19

Views: 45957

Answers (8)

NoWar
NoWar

Reputation: 37633

It works for me as well...

<%: Html.DropDownList("SportID", (SelectList)ViewData["SportsSelectList"], "-- Select --", new { @disabled = "disabled", @readonly = "readonly" })%>

<%= Html.CheckBoxFor(model => model.IsActive, new { @disabled = "disabled", @readonly = "readonly" })%>

Upvotes: 14

Bermo
Bermo

Reputation: 4931

Created an extension method on Object that will create a copy of the input object excluding any properties that are null, and return it all as dictionary that makes it easily used in MVC HtmlHelpers:

public static Dictionary<string, object> StripAnonymousNulls(this object attributes)
{
   var ret = new Dictionary<string, object>();
   foreach (var prop in attributes.GetType().GetProperties())
   {
      var val = prop.GetValue(attributes, null);
      if (val != null)
         ret.Add(prop.Name, val);
   }
   return ret;
}

Not sure about performance implications of reflecting through properties twice, and don't like the name of the extension method much, but it seems to do the job well ...

new {
       @class = "contactDetails",
       disabled = Page.User.IsInRole("administrator") ? "true" : null
    }.StripAnonymousNulls()

Upvotes: 1

hunter
hunter

Reputation: 63512

You may want to consider writing your own HtmlHelper Extension class with a new TextBox method:

public static class HtmlHelperExtensions
{
    public static MvcHtmlString TextBoxFor(this HtmlHelper htmlHelper, Expression<Func<TModel, TProperty>> expression, string cssClass, bool disabled)
    {
        return disabled 
            ? Html.TextBoxFor(expression, new {@class=cssClass, disabled="disabled"})
            : Html.TextBoxFor(expression, new {@class=cssClass})
    }
}

now (if this new class is in the same namespace, or you've imported the new namespace to your page header, or in the pages section of the web.config) you can do this on your aspx page:

<%=Html.TextBoxFor(m => m.FirstName, "contactDetails", Page.User.IsInRole("administrator")) %>

Upvotes: 1

Ollie
Ollie

Reputation: 885

Using @SLaks suggestion to use an Extension method, and using Jeremiah Clark's example Extension method I've written an extension method so I can now do

Html.TextBoxFor(m => m.FirstName,new{class='contactDetails', ...},Page.User.IsInRole("administrator"));

Not Sure if there's a better method though

public static class InputExtensions
{

    public static IDictionary<string, object> TurnObjectIntoDictionary(object data)
    {
        var attr = BindingFlags.Public | BindingFlags.Instance;
        var dict = new Dictionary<string, object>();
        if (data == null)
            return dict;
        foreach (var property in data.GetType().GetProperties(attr))
        {
            if (property.CanRead)
            {
                dict.Add(property.Name, property.GetValue(data, null));
            }
        }
        return dict;

    }

    public static MvcHtmlString TextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes, bool disabled)
    {
        IDictionary<string, object> values =  TurnObjectIntoDictionary(htmlAttributes);

        if (disabled)
            values.Add("disabled","true");


        return htmlHelper.TextBoxFor(expression, values);
    }

    public static MvcHtmlString TextAreaFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes, bool disabled)
    {
        IDictionary<string, object> values = TurnObjectIntoDictionary(htmlAttributes);

        if (disabled)
            values.Add("disabled", "true");


        return htmlHelper.TextAreaFor(expression, values);
    }

    public static MvcHtmlString CheckBoxFor<TModel>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, bool>> expression, object htmlAttributes, bool disabled)
    {
        IDictionary<string, object> values = TurnObjectIntoDictionary(htmlAttributes);

        if (disabled)
            values.Add("disabled", "true");


        return htmlHelper.CheckBoxFor(expression, values);
    }
}

Upvotes: 4

Andriy Tkach
Andriy Tkach

Reputation: 1471

You may also define this param that way:

Page.User.IsInRole("administrator")
  ? (object)new { @class='contactDetails'} 
  : (object)new { @class='contactDetails', disabled = true}

Upvotes: 1

SLaks
SLaks

Reputation: 887235

You'll need to pass a Dictionary<string, object>, and add the disabled key inside an if statement.

I recommend making an overload of the extension method that takes a bool disabled parameter and adds it to a RouteValueDictionary created from the attributes parameter if it's true. (You could also remove the disabled entry from the RouteValueDictionary if it's false, and not take another parameter)

Upvotes: 2

hunter
hunter

Reputation: 63512

Page.User.IsInRole("administrator") ? null : new { disabled = "disabled" }

Upvotes: 8

Dennis C
Dennis C

Reputation: 24747

I could suggest you to use mvccontrib.FluentHtml.

You can do something like this

 <%=this.TextBox(m=>m.FirstNam ).Disabled(Page.User.IsInRole("administrator"))%>

Upvotes: 14

Related Questions