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 ?
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;
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])));
}
}
}
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 = ""
})
}
}
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.