Установите атрибут отключения на основе условия для 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\""))
пользователь571646
источник
1
Я думаю, вам следует окружить это @ Html.Raw ()
Шади Намрути
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 Krchavý
Не работает с TextAreaFor, нужно решение для всех типов ввода
erhan355
10

Это поздно, но некоторым людям может быть полезно.

Я расширил ответ @DarinDimitrov, чтобы разрешить передачу второго объекта, который принимает любое количество логических атрибутов html, таких как disabled="disabled" checked="checked", selected="selected"и т. Д.

Атрибут будет отображаться только в том случае, если значение свойства истинно, все остальное и атрибут не будет отображаться вообще.

Настраиваемый повторно используемый 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", если выражение истинно, или полностью опущено, если ложно. Это именно то, что вам нужно.
Carsten
Это будет отображать disabled = "false" или disabled = "true", нет?
Andez
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)

Капе
источник