Как реализовать список флажков в ASP.NET Core?

Я пытаюсь реализовать контрольный список в ASP.NET Core, но столкнулся с некоторыми трудностями.

Моя ViewModel:

public class GroupIndexViewModel
{
    public Filter[] Filters { get; set; }
}

public class Filter
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool Selected { get; set; }
}

My View:

@model GroupIndexViewModel
<form asp-action="Index" asp-controller="Group" method="get">
  <ul>
  @for (var i = 0; i < Model.Filters.Length; i++)
  {
    <li>
      <input type="checkbox" id="@Model.Filters[i].Name" asp-for="@Model.Filters[i].Selected" value="@Model.Filters[i].Selected" checked="@Model.Filters[i].Selected" />
      <label for="@Model.Filters[i].Name">@Model.Filters[i].Name</label>
    </li>
  }
  </ul>
  <button type="submit" name="action">Filtrer</button>
</form>

При публикации в моем контроллере свойство Filter в моей viewmodel показывает выделенное false, даже если оно выбрано в представлении.

Ответ 1

Я бы сделал следующий путь.

@model GroupIndexViewModel
<form asp-action="Index" asp-controller="Group" method="get">
    <ul>
        @for (var i = 0; i < Model.Filters.Count; i++)
        {
            <li>       
                <input type="checkbox" asp-for="@Model.Filters[i].Selected"  />
                <label asp-for="@Model.Filters[i].Selected">@Model.Filters[i].Name</label>
                <input type="hidden" asp-for="@Model.Filters[i].Id" />
                <input type="hidden" asp-for="@Model.Filters[i].Name" />                
            </li>
        }
    </ul>
    <button type="submit" name="action">Filtrer</button>
</form>

Здесь я предполагаю, что у вас есть правильная реализация контроллера и действий.

Ответ 2

На этот вопрос уже можно было ответить, но я хотел объяснить вашу проблему, чтобы другие могли понять, что происходит.

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

Давайте посмотрим на ваш взгляд

@model GroupIndexViewModel
<form asp-action="Index" asp-controller="Group" method="get">
   <ul>
     @for (var i = 0; i < Model.Filters.Length; i++)
     {
      <li>
        <input type="checkbox" id="@Model.Filters[i].Name" asp-for="@Model.Filters[i].Selected" value="@Model.Filters[i].Selected" checked="@Model.Filters[i].Selected" />
        <label for="@Model.Filters[i].Name">@Model.Filters[i].Name</label>
     </li>
     }
  </ul>
  <button type="submit" name="action">Filtrer</button>
</form>

Итак, сначала. Вы создаете входные элементы из массива Filter. Теперь давайте внимательнее посмотрим на ваш элемент ввода.

<input type="checkbox" id="@Model.Filters[i].Name" asp-for="@Model.Filters[i].Selected" value="@Model.Filters[i].Selected" checked="@Model.Filters[i].Selected" />

Теперь позвольте мне объяснить это.

  1. Вы указываете тип, используя атрибут type.
  2. Вы указываете идентификатор, используя атрибут id.
  3. Вы связываете ввод с моделью, используя помощник по тегам asp-for.
  4. Вы указываете значение для ввода, используя атрибут value.
  5. Наконец, вы устанавливаете вход как отмеченный с помощью атрибута checked.

Если вы посмотрите Документацию по помощникам тегов, вы найдете связь между .Net Type и Input Type, понимая, что:

Флажки содержат логическое значение, соответствующее модели и отформатированное помощником тега как type="checkbox".

Поскольку вы используете атрибут type="checkbox", значение Tag Helper может быть только true или false. Итак, если мы вернемся и посмотрим на элемент ввода, вы уже указываете значение для ввода. Хотя помощник по тегам может назначить значение для ввода, он не может переопределить уже указанное. Поэтому ваш ввод всегда будет иметь указанное вами значение, в этом случае boolean по умолчанию всегда ложно.

Теперь вы можете подумать, что ваш элемент ввода имеет значение false, и, например, добавление checked="checked" не изменит значение на true, поскольку атрибуты value переопределяют checked атрибут. Причиняет плохую реализацию обоих атрибутов.

Следовательно, вы должны использовать только один атрибутов. (Либо value, либо checked). Вы можете использовать их для удобства. Но в этом случае вы должны использовать атрибут по умолчанию checked. Поскольку вы реализуете Tag Helper и входное значение, они должны иметь тип boolean. А значение атрибута checked возвращает логическое значение и, например, это значение, используемое помощником по тегам.

Таким образом, реализация, предоставляемая @dotnetstep, должна работать, так как она объявляет только вспомогательный тег в элементе input. Таким образом, Tag Helper обрабатывает соответствующие атрибуты ввода.

@model GroupIndexViewModel
<form asp-action="Index" asp-controller="Group" method="get">
    <ul>
        @for (var i = 0; i < Model.Filters.Count; i++)
        {
            <li>       
                <input type="checkbox" asp-for="@Model.Filters[i].Selected"  />
                <label asp-for="@Model.Filters[i].Selected">@Model.Filters[i].Name</label>
                <input type="hidden" asp-for="@Model.Filters[i].Id" />
                <input type="hidden" asp-for="@Model.Filters[i].Name" />                
            </li>
        }
    </ul>
    <button type="submit" name="action">Filtrer</button>
</form>

Ответ 3

Основываясь на ответе @dotnetstep, я создал помощник по тегам, который берет модель IEnumerable из SelectListItem и генерирует поля, описанные в его ответе.

Вот код помощника по тегам:

[HtmlTargetElement(Attributes = "asp-checklistbox, asp-modelname")]
public class CheckListBoxTagHelper : TagHelper
{
    [HtmlAttributeName("asp-checklistbox")]
    public IEnumerable<SelectListItem> Items { get; set; }

    [HtmlAttributeName("asp-modelname")]
    public string ModelName { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        var i = 0;
        foreach (var item in Items)
        {
            var selected = item.Selected ? @"checked=""checked""" : "";
            var disabled = item.Disabled ? @"disabled=""disabled""" : "";

            var html = [email protected]"<label><input type=""checkbox"" {selected} {disabled} id=""{ModelName}_{i}__Selected"" name=""{ModelName}[{i}].Selected"" value=""true"" /> {item.Text}</label>";
            html += [email protected]"<input type=""hidden"" id=""{ModelName}_{i}__Value"" name=""{ModelName}[{i}].Value"" value=""{item.Value}"">";
            html += [email protected]"<input type=""hidden"" id=""{ModelName}_{i}__Text"" name=""{ModelName}[{i}].Text"" value=""{item.Text}"">";

            output.Content.AppendHtml(html);

            i++;
        }

        output.Attributes.SetAttribute("class", "th-chklstbx");
    }
}

Вам нужно добавить следующее в файл _ViewImports.cshtml:

@addTagHelper *, <ProjectName>

Затем, чтобы опустить окно контрольного списка в бритву, просмотрите его так же просто, как:

<div asp-checklistbox="Model.Brands" asp-modelname="Brands"></div>

Вы можете заметить, что я добавляю атрибут класса в div для стилизации поля и его содержимого. Вот CSS:

.th-chklstbx {
  border: 1px solid #ccc;
  padding: 10px 15px;
  -webkit-border-radius: 5px ;
  -moz-border-radius: 5px ;
  -ms-border-radius: 5px ;
  border-radius: 5px ; 
}
.th-chklstbx label {
    display: block;
    margin-bottom: 10px; 
}

Ответ 4

Я только что попробовал это, и это сработало:

<input asp-for="filter.type[i].IsEnabled"/>

без флажка, а затем соответствующее логическое значение в модели со скрытым идентификатором и именем.