8

I'm trying to dynamically set the disabled attribute for the TextBoxFor HtmlHelper

@Html.TextBoxFor(model => model.Street, 
                 new
                 {
                    @class = "", 
                    disabled = (Model.StageID==(int)MyEnum.Sth) ? "disabled" : "" 
                 })

but even if there is disabled="" it is the same as disabled="disabled". How to get around of this ?

4 Answers 4

22

I have the same problem about month ago and I finished by using this extension method for it

public static class AttributesExtensions
{
    public static RouteValueDictionary DisabledIf(
        this object htmlAttributes, 
        bool disabled
    )
    {
        var attributes = new RouteValueDictionary(htmlAttributes);
        if (disabled)
        {
            attributes["disabled"] = "disabled";
        }
        return attributes;
    }
}

And after that you can use it like this

@Html.TextBoxFor(
    model => model.Street, 
    new { @class = "" }.DisabledIf(Model.StageID==(int)MyEnum.Sth)
)

EDIT (after Paul's comment):

The using of data-xxx html attributes may be mined by using the constructor of the System.Web.Routing.RouteValueDictionary class, since underscores will not be automatically converted to minus sign.

Use the method System.Web.Mvc.HtmlHelper.AnonymousObjectToHtmlAttributes instead: will solve this issue.

UPDATED CODE (Extension method body only)

var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
if (disabled)
{
    attributes["disabled"] = "disabled";
}
return attributes;
Sign up to request clarification or add additional context in comments.

4 Comments

that is quite cheeky :> but I like it. However, I'm adding a (more fragile) variant of my own
There is an issue in the accepted answer. You should call HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes) instead of new RouteValueDictionary(htmlAttributes) HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes) will convert any underscores in the html attribute names to hyphens.
Thanks @ChuckNorris and thanks too Paul for the rectification. I've just edited the answer.
I found extended ready to use version here dmenezes.com.br/blog/2014/02/05/… stealing this for my kendo UI dynamic readonly :)
0

Using the extension method below produces similar results, but this is perhaps more fragile:

@Html.TextBoxFor(
     model => model.Street, 
     new { @class = "form-control" }
).DisabledIf(Model.IsReadOnly)

Extension:

using System.Text.RegularExpressions;
using System.Web.Mvc;

namespace xxx.HtmlHelpers
{
    public static class MvcHtmlStringExtensions
    {

        private static readonly Regex OpeningTagPattern;

        static MvcHtmlStringExtensions()
        {
            OpeningTagPattern = new Regex("<[a-zA-Z]*");
        }

        public static MvcHtmlString DisabledIf(this MvcHtmlString controlHtml, bool isDisabled)
        {
            if (!isDisabled) return controlHtml;
            return
                new MvcHtmlString(OpeningTagPattern.Replace(controlHtml.ToString(),
                    x => string.Format("{0} disabled=\"disabled\"", x.Groups[0])));
        }

    }
}

1 Comment

I'm switching out my code to use Chuck Norris' version above :)
0

Probably your stage Id is not getting set

@{ 
    if(Model.StageID != null &&   Model.StageID > 0)
    {
        @Html.TextBoxFor(model => model.Street, 
             new
             {
                @class = "", 
                disabled = (Model.StageID==(int)MyEnum.Sth) ? "disabled" : "" 
             })
    }else{

        @Html.TextBoxFor(model => model.Street, 
             new
             {
                @class = ""
             })
    }
}

Comments

0

We actually just ran into the same problem. We ended up implementing an extension method with overloaded parameters, which takes in a boolean indicating whether or not we want the control disabled. We just add the "disabled" attribute when appropriate, and let the built-in HtmlHelper handle the heavy lifting.

Extension class and method:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
public static class OurHtmlHelpers
{
    public const string DisabledAttribute = "disabled";

    public static MvcHtmlString TextBoxFor<TModel, TProp>(this HtmlHelper<TModel> htmlHelper, 
                                                            Expression<Func<TModel, TProp>> expression, 
                                                            object htmlAttributes, 
                                                            bool canEdit)
    {
        var htmlAttributeDictionary = SetDisabledAttribute(htmlAttributes, canEdit);

        return htmlHelper.TextBoxFor(expression, htmlAttributeDictionary);
    }        

    private static RouteValueDictionary SetDisabledAttribute(object htmlAttributes, bool canEdit)
    {
        var htmlAttributeDictionary = new RouteValueDictionary(htmlAttributes);

        if (!canEdit)
        {
            htmlAttributeDictionary.Add(DisabledAttribute, DisabledAttribute);
        }

        return htmlAttributeDictionary;
    }
}

Then you just need to reference your new class and call @Html.TextBoxFor(m => m.SomeValue, new { @class = "someClass" }, <Your bool value>)

It's worth noting that you'd have to define these extensions for any of the TextBoxFor overloads you'd like to use, but it seems like a reasonable trade off. You can also utilize most of the same code for other HtmlHelpers you'd like to add the functionality to.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.