根据 Html.TextBoxFor 的条件设置禁用属性

我想在 asp.net MVC 中根据 Html.TextBoxFor 的条件设置禁用属性,如下所示

@Html.TextBoxFor(model => model.ExpireDate, new { style = "width: 70px;", maxlength = "10", id = "expire-date" disabled = (Model.ExpireDate == null ? "disable" : "") })

这个帮助程序有两个输出兵禁用 = “残疾人”或残疾人 = “”。两个主题都使文本框禁用。

如果 Model.ExpireDate = = null else 我想启用它,我想禁用文本框

154406 次浏览

The valid way is:

disabled="disabled"

Browsers also might accept disabled="" but I would recommend you the first approach.

Now this being said I would recommend you writing a custom HTML helper in order to encapsulate this disabling functionality into a reusable piece of code:

using System;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;


public static class HtmlExtensions
{
public static IHtmlString MyTextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes,
bool disabled
)
{
var attributes = new RouteValueDictionary(htmlAttributes);
if (disabled)
{
attributes["disabled"] = "disabled";
}
return htmlHelper.TextBoxFor(expression, attributes);
}
}

which you could use like this:

@Html.MyTextBoxFor(
model => model.ExpireDate,
new {
style = "width: 70px;",
maxlength = "10",
id = "expire-date"
},
Model.ExpireDate == null
)

and you could bring even more intelligence into this helper:

public static class HtmlExtensions
{
public static IHtmlString MyTextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes
)
{
var attributes = new RouteValueDictionary(htmlAttributes);
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
if (metaData.Model == null)
{
attributes["disabled"] = "disabled";
}
return htmlHelper.TextBoxFor(expression, attributes);
}
}

so that now you no longer need to specify the disabled condition:

@Html.MyTextBoxFor(
model => model.ExpireDate,
new {
style = "width: 70px;",
maxlength = "10",
id = "expire-date"
}
)

I like Darin method. But quick way to solve this,

Html.TextBox("Expiry", null, new { style = "width: 70px;", maxlength = "10", id = "expire-date", disabled = "disabled" }).ToString().Replace("disabled=\"disabled\"", (1 == 2 ? "" : "disabled=\"disabled\""))

Another approach is to disable the text box on the client side.

In your case you have only one textbox that you need to disable but consider the case where you have multiple input, select, and textarea fields that yout need to disable.

It is much easier to do it via jquery + (since we can not rely on data coming from the client) add some logic to the controller to prevent these fields from being saved.

Here is an example:

<input id="document_Status" name="document.Status" type="hidden" value="2" />


$(document).ready(function () {


disableAll();
}


function disableAll() {
var status = $('#document_Status').val();


if (status != 0) {
$("input").attr('disabled', true);
$("textarea").attr('disabled', true);
$("select").attr('disabled', true);
}
}

This is late, but may be helpful to some people.

I have extended @DarinDimitrov's answer to allow for passing a second object that takes any number of boolean html attributes like disabled="disabled" checked="checked", selected="selected" etc.

It will render the attribute only if the property value is true, anything else and the attribute will not be rendered at all.

The custom reuseble HtmlHelper:

public static class HtmlExtensions
{
public static IHtmlString MyTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes,
object booleanHtmlAttributes)
{
var attributes = new RouteValueDictionary(htmlAttributes);


//Reflect over the properties of the newly added booleanHtmlAttributes object
foreach (var prop in booleanHtmlAttributes.GetType().GetProperties())
{
//Find only the properties that are true and inject into the main attributes.
//and discard the rest.
if (ValueIsTrue(prop.GetValue(booleanHtmlAttributes, null)))
{
attributes[prop.Name] = prop.Name;
}
}


return htmlHelper.TextBoxFor(expression, attributes);
}


private static bool ValueIsTrue(object obj)
{
bool res = false;
try
{
res = Convert.ToBoolean(obj);
}
catch (FormatException)
{
res = false;
}
catch(InvalidCastException)
{
res = false;
}
return res;
}


}

Which you can use like so:

@Html.MyTextBoxFor(m => Model.Employee.Name
, new { @class = "x-large" , placeholder = "Type something…" }
, new { disabled = true})

Yet another solution would be to create a Dictionary<string, object> before calling TextBoxFor and pass that dictionary. In the dictionary, add "disabled" key only if the textbox is to be diabled. Not the neatest solution but simple and straightforward.

One simple approach I have used is conditional rendering:

@(Model.ExpireDate == null ?
@Html.TextBoxFor(m => m.ExpireDate, new { @disabled = "disabled" }) :
@Html.TextBoxFor(m => m.ExpireDate)
)

Actually, the internal behavior is translating the anonymous object to a dictionary. So what I do in these scenarios is go for a dictionary:

@{
var htmlAttributes = new Dictionary<string, object>
{
{ "class" , "form-control"},
{ "placeholder", "Why?" }
};
if (Model.IsDisabled)
{
htmlAttributes.Add("disabled", "disabled");
}
}
@Html.EditorFor(m => m.Description, new { htmlAttributes = htmlAttributes })

Or, as Stephen commented here:

@Html.EditorFor(m => m.Description,
Model.IsDisabled ? (object)new { disabled = "disabled" } : (object)new { })

I achieved it using some extension methods

private const string endFieldPattern = "^(.*?)>";


public static MvcHtmlString IsDisabled(this MvcHtmlString htmlString, bool disabled)
{
string rawString = htmlString.ToString();
if (disabled)
{
rawString = Regex.Replace(rawString, endFieldPattern, "$1 disabled=\"disabled\">");
}


return new MvcHtmlString(rawString);
}


public static MvcHtmlString IsReadonly(this MvcHtmlString htmlString, bool @readonly)
{
string rawString = htmlString.ToString();
if (@readonly)
{
rawString = Regex.Replace(rawString, endFieldPattern, "$1 readonly=\"readonly\">");
}


return new MvcHtmlString(rawString);
}

and then....

@Html.TextBoxFor(model => model.Name, new { @class= "someclass"}).IsDisabled(Model.ExpireDate == null)

Is solved this using RouteValueDictionary (works fine as htmlAttributes as it's based on IDictionary) and an extension method:

public static RouteValueDictionary AddIf(this RouteValueDictionary dict, bool condition, string name, object value)
{
if (condition) dict.Add(name, value);
return dict;
}

Usage:

@Html.TextBoxFor(m => m.GovId, new RouteValueDictionary(new { @class = "form-control" })
.AddIf(Model.IsEntityFieldsLocked, "disabled", "disabled"))

Credit goes to https://stackoverflow.com/a/3481969/40939

if you dont want to use Html Helpers take look it my solution

disabled="@(your Expression that returns true or false")"

that it

@{
bool isManager = (Session["User"] as User).IsManager;
}
<textarea rows="4" name="LetterManagerNotes" disabled="@(!isManager)"></textarea>

and I think the better way to do it is to do that check in the controller and save it within a variable that is accessible inside the view(Razor engine) in order to make the view free from business logic

If you don't use html helpers you may use simple ternary expression like this:

<input name="Field"
value="@Model.Field" tabindex="0"
@(Model.IsDisabledField ? "disabled=\"disabled\"" : "")>

I like the extension method approach so you don't have to pass through all possible parameters.
However using Regular expressions can be quite tricky (and somewhat slower) so I used XDocument instead:

public static MvcHtmlString SetDisabled(this MvcHtmlString html, bool isDisabled)
{
var xDocument = XDocument.Parse(html.ToHtmlString());
if (!(xDocument.FirstNode is XElement element))
{
return html;
}


element.SetAttributeValue("disabled", isDisabled ? "disabled" : null);
return MvcHtmlString.Create(element.ToString());
}

Use the extension method like this:
@Html.EditorFor(m => m.MyProperty).SetDisabled(Model.ExpireDate == null)