Đặt thuộc tính vô hiệu hóa dựa trên điều kiện cho Html.TextBoxFor


81

Tôi muốn đặt thuộc tính vô hiệu hóa dựa trên điều kiện cho Html.TextBoxFor trong asp.net MVC như bên dưới

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

Trình trợ giúp này có hai đầu ra bị vô hiệu hóa = "vô hiệu hóa" hoặc bị vô hiệu hóa = "". cả hai chủ đề làm cho hộp văn bản bị vô hiệu hóa.

Tôi muốn vô hiệu hóa hộp văn bản nếu Model.ExpireDate == null nếu không, tôi muốn bật nó


Hãy xem câu trả lời của tôi tại đây: stackoverflow.com/a/43131930/6680521
Extragorey

Câu trả lời:


85

Cách hợp lệ là:

disabled="disabled"

Các trình duyệt cũng có thể chấp nhận disabled="" nhưng tôi muốn giới thiệu cho bạn cách tiếp cận đầu tiên.

Bây giờ điều này đang được nói, tôi khuyên bạn nên viết một trình trợ giúp HTML tùy chỉnh để đóng gói chức năng vô hiệu hóa này thành một đoạn mã có thể sử dụng lại:

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);
    }
}

mà bạn có thể sử dụng như thế này:

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

và bạn có thể mang lại nhiều thông tin hơn nữa cho người trợ giúp này:

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);
    }
}

để bây giờ bạn không cần chỉ định điều kiện bị vô hiệu hóa nữa:

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

Tôi muốn vô hiệu hóa các textbox nếu Model.ExpireDate == null khác tôi muốn kích hoạt nó
Ghooti Farangi

4
Giải pháp này thật tuyệt vời - nếu nó đi ... .) Lý tưởng nhất là một cái gì đó hoạt động nội tuyến với những cái hiện có. Tôi đã xây dựng một giải pháp về cơ bản chỉ bao bọc đối tượng ẩn danh và trả về một RouteValueDictionary - nhưng nó không cảm thấy đặc biệt rõ ràng.
Mir

3
"vô hiệu hóa", "vô hiệu hóa = ''" và "vô hiệu hóa = 'vô hiệu hóa'" đều có giá trị như nhau trong html và thật gây hiểu lầm (và sai) khi nói rằng những cái ngắn hơn chỉ có thể được các trình duyệt khác nhau chấp nhận . Cf dev.w3.org/html5/markup/syntax.html#syntax-attr-empty
Shautieh 24/09/13

53

Trên thực tế, hành vi bên trong đang dịch đối tượng ẩn danh sang từ điển. Vì vậy, những gì tôi làm trong các tình huống này là tìm từ điển:

@{
  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 })

Hoặc, như Stephen đã nhận xét ở đây :

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

@ Html.EditorFor (m => m.Description, Model.IsDisabled? (Object) new {disable = "disable"}: (object) new {}) => đây có vẻ là cách tốt nhất. Cảm ơn
Carmine Checker

23

Tôi thích phương pháp Darin. Nhưng cách nhanh chóng để giải quyết vấn đề này,

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

1
Tôi nghĩ bạn nên bao quanh này với @ Html.Raw ()
Shadi Namrouti

14

Một cách tiếp cận đơn giản mà tôi đã sử dụng là kết xuất có điều kiện:

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

13

Nếu bạn không sử dụng trình trợ giúp html, bạn có thể sử dụng biểu thức bậc ba đơn giản như sau:

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

13

Tôi đã đạt được nó bằng cách sử dụng một số phương pháp mở rộng

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);
    }

và sau đó....

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

Hoạt động nếu bạn thay đổi chuỗi thô. Độ dài - 2 cho 7 và thêm "" vào sau ".
Jozef Krchňavý

Không hoạt động với TextAreaFor, cần giải pháp cho tất cả các loại đầu vào
erhan355

10

Điều này là muộn, nhưng có thể hữu ích với một số người.

Tôi đã mở rộng câu trả lời của @ DarinDimitrov để cho phép chuyển đối tượng thứ hai có bất kỳ số lượng thuộc tính html boolean nào như disabled="disabled" checked="checked", selected="selected"v.v.

Nó sẽ chỉ hiển thị thuộc tính nếu giá trị thuộc tính là true, bất kỳ thứ gì khác và thuộc tính sẽ hoàn toàn không được hiển thị.

HtmlHelper có thể tái sử dụng tùy chỉnh:

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;
    }

}

Bạn có thể sử dụng như vậy:

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

10

Điều này được giải quyết bằng cách sử dụng RouteValueDictionary (hoạt động tốt như htmlAttributes vì ​​nó dựa trên IDictionary) và một phương thức mở rộng:

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

Sử dụng:

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

Tín dụng được chuyển đến https://stackoverflow.com/a/3481969/40939


IMHO, đây là câu trả lời hay nhất
JenonD

6

nếu bạn không muốn sử dụng Html Helpers, hãy xem nó là giải pháp của tôi

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

rằng nó

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

và tôi nghĩ cách tốt hơn để làm điều đó là kiểm tra trong bộ điều khiển và lưu nó trong một biến có thể truy cập bên trong chế độ xem (công cụ Razor) để thực hiện the view free from business logic


7
Nếu bạn sử dụng thuộc tính bị vô hiệu hóa trong một điều khiển, thì điều khiển đó sẽ bị vô hiệu hóa bất kể thuộc tính đó có giá trị nào. Ngay cả sự hiện diện của thuộc tính không có giá trị cũng sẽ vô hiệu hóa điều khiển.
Geeky Guy

2
Giải pháp này hoạt động thực sự tốt, và tôi nghi ngờ những người phản đối có thể đã bỏ qua rằng biểu thức là boolean. Khi biểu thức là boolean, thuộc tính bị vô hiệu hóa sẽ hiển thị là disable = "disable" nếu biểu thức là true hoặc bị bỏ qua hoàn toàn nếu false. Đó là chính xác những gì bạn muốn.
Carsten

Điều này sẽ hiển thị vô hiệu hóa = "false" hoặc vô hiệu hóa = "true", không?
Andez

4

Tuy nhiên, một giải pháp khác sẽ là tạo một Dictionary<string, object>trước khi gọi TextBoxForvà chuyển từ điển đó. Trong từ điển, chỉ thêm "disabled"khóa nếu hộp văn bản bị tắt. Không phải là giải pháp gọn gàng nhất nhưng đơn giản và dễ hiểu.


2

Một cách tiếp cận khác là vô hiệu hóa hộp văn bản ở phía máy khách.

Trong trường hợp của bạn, bạn chỉ có một hộp văn bản cần tắt nhưng hãy xem xét trường hợp bạn có nhiều trường nhập, chọn và vùng văn bản mà bạn cần phải tắt.

Nó dễ dàng hơn nhiều để làm điều đó thông qua jquery + (vì chúng tôi không thể dựa vào dữ liệu đến từ máy khách) thêm một số logic vào bộ điều khiển để ngăn các trường này được lưu.

Đây là một ví dụ:

<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);
  }
}

0

Tôi thích cách tiếp cận phương pháp mở rộng để bạn không phải chuyển qua tất cả các tham số có thể.
Tuy nhiên, việc sử dụng Biểu thức chính quy có thể khá phức tạp (và hơi chậm hơn) nên tôi đã sử dụng XDocumentthay thế:

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());
}

Sử dụng phương pháp mở rộng như sau:
@Html.EditorFor(m => m.MyProperty).SetDisabled(Model.ExpireDate == null)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.