tags:

views:

1126

answers:

6

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

+2  A: 

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)

SLaks
If you do that it will still render out a "disabled" attribute and most browsers will treat that as disabled regardless of disabled="disabled"
hunter
Then you'll need to use a dictionary.
SLaks
+4  A: 

I could suggest you to use mvccontrib.FluentHtml.

You can do something like this

 <%=this.TextBox(m=>m.FirstNam ).Disabled(Page.User.IsInRole("administrator"))%>
Dennis Cheung
Wow, that's pretty. Definately checking that out this weekend!
George R
+1  A: 

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

hunter
+1 Good idea... (Unless he needs other attributes)
SLaks
I need other attributes - code repetition is what I'm trying to avoid
Ollie
A: 

You may also define this param that way:

Page.User.IsInRole("administrator")
  ? (object)new { @class='contactDetails'} 
  : (object)new { @class='contactDetails', disabled = true}
Andrey Tkach
It's the code repetition I'm trying to avoid - when you have a lot of attributes this gets just as messy
Ollie
Not sure I really like the readability of it also, but when using anonymous types you have to create multiple instances for each set of attributes.
Andrey Tkach
+1  A: 

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);
    }
}
Ollie
You should replace your `TurnObjectIntoDictionary` method with a `RouteValueDictionary`, which is what all of the extension methods use. It should be faster. Also, you should accept my answer.
SLaks
BTW, anyone trying this will need 'using System.Web.Mvc' and 'using System.Web.Mvc.Html'
rohancragg
A: 

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")) %>
hunter