Встановіть атрибут вимкнення на основі умови для Html.TextBoxFor


81

Я хочу встановити атрибут вимкнення на основі умови для Html.TextBoxFor в asp.net MVC, як показано нижче

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

Цей помічник має два виходи disabled = "disabled" або disabled = "". обидві теми роблять текстове поле відключеним.

Я хочу вимкнути текстове поле, якщо Model.ExpireDate == null ще я хочу його увімкнути


Подивіться на мою відповідь тут: stackoverflow.com/a/43131930/6680521
Extragorey

Відповіді:


85

Дійсний спосіб:

disabled="disabled"

Браузери також можуть прийняти, disabled="" але я рекомендую вам перший підхід.

Тепер, кажучи про те, що я рекомендую вам написати власний помічник HTML, щоб інкапсулювати цю функцію відключення у шматок коду, що використовується багаторазово:

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

які ви могли б використовувати так:

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

і ви могли б внести ще більше розуму в цього помічника:

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

так що тепер вам більше не потрібно вказувати вимкнений стан:

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

Я хочу відключити текстове поле, якщо Model.ExpireDate == null ще я хочу його увімкнути
Ghooti Farangi

4
Це рішення чудове - наскільки це можливо ... але було б непогано знайти чисте рішення, яке не вимагає розміщення обгортки навколо кожного використовуваного нами HtmlHelper, який може мати відключений атрибут (TextBoxFor, TextAreaFor, CheckBoxFor тощо) .) В ідеалі те, що працює в рамках існуючих. Я створив рішення, яке в основному просто обгортає анонімний об'єкт і повертає RouteValueDictionary - але воно не відчуває себе особливо чисто.
Мір

3
"disabled", "disabled = ''" та "disabled = 'disabled'" однаково справедливі в html, і оманливим (і помилковим) є твердження, що коротші можуть прийматись лише різними браузерами. Пор. dev.w3.org/html5/markup/syntax.html#syntax-attr-empty
Shautieh

53

Власне, внутрішня поведінка - це переклад анонімного об’єкта у словник. Отже, у цих сценаріях я роблю словник:

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

Або, як прокоментував тут Стівен :

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

@ Html.EditorFor (m => m.Description, Model.IsDisabled? (Object) new {disabled = "disabled"}: (object) new {}) => це видається найкращим способом. Дякую
Carmine Checker

23

Мені подобається метод Дарина. Але швидкий спосіб вирішити це,

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

1
Думаю, вам слід оточити це @ Html.Raw ()
Shadi Namrouti

14

Один простий підхід, який я використав, - це умовний візуалізація:

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

13

Якщо ви не використовуєте HTML-помічники, ви можете використовувати простий тернарний вираз, такий:

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

13

Я домігся цього, використовуючи деякі методи розширення

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

і потім....

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

Працює, якщо змінити rawstring.Length - 2 на 7 і додати "" після останнього ".
Jozef Krchňavý

Не працює з TextAreaFor, потрібне рішення для всіх типів введення
erhan355,

10

Це пізно, але може бути корисним для деяких людей.

Я розширив відповідь @ DarinDimitrov, щоб дозволити передачу другого об'єкта, який приймає будь-яку кількість булевих атрибутів html, таких як disabled="disabled" checked="checked", selected="selected" тощо.

Він відображатиме атрибут лише за умови, що значення властивості має значення true, а інше та атрибут взагалі не відображатимуться.

Спеціальний багаторазовий 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;
    }

}

Які ви можете використовувати так:

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

10

Вирішується це за допомогою RouteValueDictionary (чудово працює як htmlAttributes, оскільки він базується на IDictionary) та методу розширення:

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

Використання:

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

Кредит надходить на https://stackoverflow.com/a/3481969/40939


ІМХО, це найкраща відповідь
JenonD

6

якщо ви не хочете використовувати Html Helpers, подивіться, це моє рішення

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

що це

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

і я думаю, що кращий спосіб це зробити - перевірити контролер і зберегти його в змінній, доступній всередині подання (движок Razor), щоб зробити the view free from business logic


7
Якщо ви використовуєте атрибут disabled у елементі керування, елемент керування буде вимкнено незалежно від того, яке значення має атрибут. Навіть наявність атрибута без значення вимкне керування.
Geeky Guy,

2
Це рішення працює дуже добре, і я підозрюю, що голоси прихильників могли пропустити, що вираз є логічним. Коли вираз логічний, атрибут disabled відображатиметься як disabled = "disabled", якщо вираз істинно, або буде повністю опущений, якщо false. Що саме те, що ви хочете.
Карстен,

Це буде робити або disabled = "false", або disabled = "true", ні?
Андез,

4

Ще одним рішенням було б створити Dictionary<string, object>перед викликом TextBoxForта передати цей словник. У словнику додайте "disabled"клавішу лише для того, щоб вводити текстове поле. Не найоптимальніше рішення, але просте і зрозуміле.


2

Інший підхід - вимкнути текстове поле на стороні клієнта.

У вашому випадку у вас є лише одне текстове поле, яке вам потрібно відключити, але враховуйте випадок, коли у вас є кілька полів введення, вибору та текстових областей, які вам потрібно відключити.

Набагато простіше це зробити за допомогою jquery + (оскільки ми не можемо покладатися на дані, що надходять від клієнта), додайте трохи контролера, щоб запобігти збереженню цих полів.

Ось приклад:

<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

Мені подобається підхід до методу розширення, тому вам не потрібно проходити всі можливі параметри.
Однак використання регулярних виразів може бути досить складним (і дещо повільнішим), тому я XDocumentзамість цього використав :

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

Використовуйте метод розширення таким чином:
@Html.EditorFor(m => m.MyProperty).SetDisabled(Model.ExpireDate == null)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.