Как условно отключить ‹select› из помощника по тегам?

Моя цель — условно отключить раскрывающийся список в зависимости от статуса объекта модели, переданного в представление.

Следующий код правильно отображает отключенный тег <select> (но не условно):

<select class="form-control" asp-for="Priority" asp-items="@priorityList" disabled></select>

Следующее нет. Атрибут disabled не отображается в исходном коде отображаемой страницы:

@{ string disabled = Model.CaseMode == Mode.Active ? "" : "disabled"; }
<select class="form-control" asp-for="Priority" asp-items="@priorityList" @disabled></select>

Кроме того, следующее также не отключает тег <select>.

<select class="form-control" asp-for="Priority" asp-items="@priorityList" @((Model.CaseMode == Mode.Closed) ? "disabled" : "")></select>

Я предполагаю, что проблема связана с тем, что вспомогательная функция тега обрабатывает тег <select> до того, как в шаблоне будет выполнена замена строки. Может ли кто-нибудь предложить, как я могу условно отключить этот элемент без необходимости отображать два отдельных элемента в структуре if else?


person Larry Lustig    schedule 07.08.2017    source источник


Ответы (3)


Это невозможно с помощью помощника по тегу select по умолчанию, но вы можете создать свой собственный и настроить его так, чтобы он реагировал на пользовательский атрибут asp-disabled, который принимает логическое значение.

На ваш взгляд:

<select class="form-control" asp-for="Priority" asp-items="@priorityList" asp-disabled="@(Model.CaseMode == Mode.Closed)"></select>

Затем создайте свой класс TagHelper:

using Microsoft.AspNetCore.Razor.TagHelpers;
using System;

namespace YourNamespace.TagHelpers
{
    // Triggered on all select elements with the asp-disabled attribute
    [HtmlTargetElement("select", Attributes = DisabledAttributeName)]
    public class SelectTagHelper : TagHelper
    {
        private const string DisabledAttributeName = "asp-disabled";

        /// Get the value of the condition
        [HtmlAttributeName(DisabledAttributeName)]
        public bool Disabled { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if (context == null)
                throw new ArgumentNullException(nameof(context));

            if (output == null)
                throw new ArgumentNullException(nameof(output));

            if (Disabled)
                output.Attributes.SetAttribute("disabled", null);
        }
    }
}

Чтобы убедиться, что ваш TagHelper используется, вам также необходимо зарегистрировать его в _ViewImports.cshtml:

@addTagHelper *, YourNamespace
person Métoule    schedule 08.08.2017
comment
Спасибо. Я полагаю, это дополнение к существующему вспомогательному тегу <select>, который поставляется с фреймворком? - person Larry Lustig; 08.08.2017
comment
Да, это добавка. Обратите внимание, что вы можете изменить порядок, в котором вызываются вспомогательные функции тегов, перегрузив свойство Order (нижний выполняется раньше), но здесь это не требуется, поскольку коллизии нет. - person Métoule; 08.08.2017
comment
Спасибо, я создал модифицированную версию, которая позволяет мне передать перечисление Active, ReadOnly или Disabled. Когда я создал метод Process, Studio включила вызов base(context, output). Вы знаете, если это строго требуется? - person Larry Lustig; 09.08.2017
comment
На самом деле, я вернулся назад и переписал помощник тега, чтобы вместо этого отображать <select> как <input> только для чтения (чтобы избежать проблемы с отсутствием обратной передачи). - person Larry Lustig; 09.08.2017

Нет необходимости создавать собственный TagHelper. Попробуй это.

<select class="form-control" asp-for="Priority" asp-items="@priorityList" disabled="@(true)"></select>
<select class="form-control" asp-for="Priority" asp-items="@priorityList" disabled="@(false)"></select>

Этот рендер:

<select class="form-control" id="Priority" name="Priority" disabled="disabled">...</select>
<select class="form-control" id="Priority" name="Priority">...</select>

Я понял это отсюда: https://github.com/aspnet/Mvc/issues/7333#issuecomment-363504164

person tsu1980    schedule 07.03.2018
comment
Это действительно намного проще. - person Métoule; 07.03.2018
comment
Спасибо, намного проще. Я не думаю, что мне это нравится - он считает, что должен отображать disabled="true" и disabled="false". Но, я думаю, это то, что мы должны делать. - person Larry Lustig; 07.03.2018
comment
disabled="false" не делает выбор активным. Вот почему disabled="@(true)" не работает. - person Ratul; 23.05.2020
comment
@ Ратул прав. отключенный атрибут html не имеет =true или =false. На самом деле, если вы используете ‹select disabled=false.../›, он все равно будет отображаться как отключенный, потому что все, что он ищет, это отключенный атрибут. - person Michael Gervasoni; 03.09.2020

Поскольку disabled=false у меня не сработало и я не хотел добавлять класс расширения только для одного списка выбора... вот как я это решил:

@{ string disabled = Model.CaseMode == Mode.Active ? "disabled" : null; }
<select  asp-for="Priority" class="form-control" disabled="@disabled" asp-items="@priorityList"></select>

Другим возможным решением было бы иметь ваше условие в словаре ViewData и оценивать его после загрузки документа:

@if((bool)ViewData["YourModelCondition"]){
     $('#selectListID').prop('disabled', 'disabled');
}

Примечание. Вам нужно будет указать идентификатор для выбора, если вы используете второе решение.

person Nahuel Gonzalez    schedule 07.08.2020