Выберите Tag Helper в ASP.NET Core MVC

Мне нужна помощь с помощником по тегу select в ASP.NET Core.

У меня есть список сотрудников, которых я пытаюсь привязать к помощнику по тегу select. Мои сотрудники находятся в List<Employee> EmployeesList и выбранное значение войдет в EmployeeId имущество. Моя модель зрения выглядит так:

public class MyViewModel
{
   public int EmployeeId { get; set; }
   public string Comments { get; set; }
   public List<Employee> EmployeesList {get; set; }
}

Мой класс сотрудников выглядит так:

public class Employee
{
   public int Id { get; set; }
   public string FullName { get; set; }
}

Мой вопрос заключается в том, как сказать помощнику по тегу select использовать Id в качестве значения при отображении FullName в выпадающем списке?

<select asp-for="EmployeeId" asp-items="???" />

Я был бы признателен за помощь в этом. Благодарю.

7 ответов

Решение

Использование помощников Select Tag для визуализации элемента SELECT в вашем представлении

В вашем действии GET создайте объект вашей модели представления, загрузите EmployeeList Соберите свойство и отправьте его на просмотр.

public IActionResult Create()
{
    var vm = new MyViewModel();
    vm.EmployeesList = new List<Employee>
    {
        new Employee { Id = 1, FullName = "Shyju" },
        new Employee { Id = 2, FullName = "Bryan" }
    };
    return View(vm);
}

И в вашем представлении создать, создать новый SelectList объект из EmployeeList свойство и передать его в качестве значения для asp-items имущество.

@model MyViewModel
<form asp-controller="Home" asp-action="Create">

    <select asp-for="EmployeeId" 
            asp-items="@(new SelectList(Model.EmployeesList,"Id","FullName"))">
        <option>Please select one</option>
    </select>

    <input type="submit"/>

</form>

И ваш метод действия HttpPost для принятия отправленных данных формы.

[HttpPost]
public IActionResult Create(MyViewModel model)
{
   //  check model.EmployeeId 
   //  to do : Save and redirect
}

Или же

Если ваша модель просмотра имеет List<SelectListItem> как свойство для ваших выпадающих элементов.

public class MyViewModel
{
    public int EmployeeId { get; set; }
    public string Comments { get; set; }
    public List<SelectListItem> Employees { set; get; }
}

И в твоих действиях,

public IActionResult Create()
{
    var vm = new MyViewModel();
    vm.Employees = new List<SelectListItem>
    {
        new SelectListItem {Text = "Shyju", Value = "1"},
        new SelectListItem {Text = "Sean", Value = "2"}
    };
    return View(vm);
}

И в представлении, вы можете напрямую использовать Employees собственность для asp-items,

@model MyViewModel
<form asp-controller="Home" asp-action="Create">

    <label>Comments</label>
    <input type="text" asp-for="Comments"/>

    <label>Lucky Employee</label>
    <select asp-for="EmployeeId" asp-items="@Model.Employees" >
        <option>Please select one</option>
    </select>

    <input type="submit"/>

</form>

Класс SelectListItem принадлежит Microsoft.AspNet.Mvc.Rendering Пространство имен.

Убедитесь, что вы используете явный закрывающий тег для элемента select. Если вы используете подход самозакрывающегося тега, помощник тегов отобразит пустой элемент SELECT!

Подход ниже не будет работать

<select asp-for="EmployeeId" asp-items="@Model.Employees" />

Но это будет работать.

<select asp-for="EmployeeId" asp-items="@Model.Employees"></select>

Получение данных из таблицы базы данных с использованием структуры сущностей

Приведенные выше примеры используют жестко закодированные элементы для параметров. Поэтому я подумал, что добавлю некоторый пример кода для получения данных, используя Entity Framework, так как многие люди используют это.

Давайте предположим, что у вашего объекта DbContext есть свойство с именем Employees, который имеет тип DbSet<Employee> где Employee класс сущности имеет Id а также Name свойство как это

public class Employee
{
   public int Id { set; get; }
   public string Name { set; get; }
}

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

public IActionResult Create()
{
    var vm = new MyViewModel();
    vm.Employees = context.Employees
                          .Select(a => new SelectListItem() {  
                              Value = a.Id.ToString(),
                              Text = a.Name
                          })
                          .ToList();
    return View(vm);
}

Если предположить, context это ваш объект контекста БД. Код представления такой же, как указано выше.

Использование SelectList

Некоторые люди предпочитают использовать SelectList класс для хранения элементов, необходимых для визуализации параметров.

public class MyViewModel
{
    public int EmployeeId { get; set; }
    public SelectList Employees { set; get; }
}

Теперь в вашем действии GET вы можете использовать SelectList конструктор для заполнения Employees свойство модели представления. Убедитесь, что вы указываете dataValueField а также dataTextField параметры.

public IActionResult Create()
{
    var vm = new MyViewModel();
    vm.Employees = new SelectList(GetEmployees(),"Id","FirstName");
    return View(vm);
}
public IEnumerable<Employee> GetEmployees()
{
    return new List<Employee>
    {
        new Employee { Id=1, FirstName="Shyju"},
        new Employee { Id=2, FirstName="Bryan"}
    };
}

Здесь я звоню GetEmployees метод, чтобы получить список объектов Employee, каждый с Id а также FirstName собственность, и я использую эти свойства как DataValueField а также DataTextField из SelectList объект, который мы создали. Вы можете изменить жестко закодированный список на код, который считывает данные из таблицы базы данных.

Код вида будет таким же.

<select asp-for="EmployeeId" asp-items="@Model.Employees" >
    <option>Please select one</option>
</select>

Визуализируйте элемент SELECT из списка строк.

Иногда вы можете захотеть визуализировать элемент select из списка строк. В этом случае вы можете использовать SelectList конструктор, который принимает только IEnumerable<T>

var vm = new MyViewModel();
var items = new List<string> {"Monday", "Tuesday", "Wednesday"};
vm.Employees = new SelectList(items);
return View(vm);

Код вида будет таким же.

Настройка выбранных параметров

Иногда может потребоваться установить один параметр в качестве параметра по умолчанию в элементе SELECT (например, на экране редактирования вы хотите загрузить ранее сохраненное значение параметра). Для этого вы можете просто установить EmployeeId Значение свойства к значению опции, которую вы хотите выбрать.

public IActionResult Create()
{
    var vm = new MyViewModel();
    vm.Employees = new List<SelectListItem>
    {
        new SelectListItem {Text = "Shyju", Value = "11"},
        new SelectListItem {Text = "Tom", Value = "12"},
        new SelectListItem {Text = "Jerry", Value = "13"}
    };
    vm.EmployeeId = 12;  // Here you set the value
    return View(vm);
}

Это выберет опцию Tom в элементе select при визуализации страницы.

Раскрывающийся список

Если вы хотите отобразить раскрывающийся список с множественным выбором, вы можете просто изменить свойство модели представления, которое вы используете для asp-for атрибут в вашем представлении к типу массива.

public class MyViewModel
{
    public int[] EmployeeIds { get; set; }
    public List<SelectListItem> Employees { set; get; }
}

Это отобразит HTML-разметку для элемента select с multiple атрибут, который позволит пользователю выбрать несколько вариантов.

@model MyViewModel
<select id="EmployeeIds" multiple="multiple" name="EmployeeIds">
    <option>Please select one</option>
    <option value="1">Shyju</option>
    <option value="2">Sean</option>
</select>

Настройка выбранных опций в мультиселекте

Подобно одиночному выбору, установите EmployeeIds Значение свойства в массив значений, которые вы хотите.

public IActionResult Create()
{
    var vm = new MyViewModel();
    vm.Employees = new List<SelectListItem>
    {
        new SelectListItem {Text = "Shyju", Value = "11"},
        new SelectListItem {Text = "Tom", Value = "12"},
        new SelectListItem {Text = "Jerry", Value = "13"}
    };
    vm.EmployeeIds= new int[] { 12,13} ;  
    return View(vm);
}

Это выберет опцию Том и Джерри в элементе множественного выбора при визуализации страницы.

Использование ViewBag для передачи списка элементов

Если вы не предпочитаете сохранять свойство типа коллекции для передачи списка опций представлению, вы можете использовать для этого динамический ViewBag (это не мой личный рекомендуемый подход, так как viewbag является динамическим, и ваш код склонен к необработанному). опечатки)

public IActionResult Create()
{       
    ViewBag.Employees = new List<SelectListItem>
    {
        new SelectListItem {Text = "Shyju", Value = "1"},
        new SelectListItem {Text = "Sean", Value = "2"}
    };
    return View(new MyViewModel());
}

и в представлении

<select asp-for="EmployeeId" asp-items="@ViewBag.Employees">
    <option>Please select one</option>
</select>

Группировка товаров

Вспомогательный метод select tag поддерживает параметры группировки в раскрывающемся списке. Все, что вам нужно сделать, это указать Group значение свойства каждого SelectListItem в вашем методе действия.

public IActionResult Create()
{
    var vm = new MyViewModel();

    var group1 = new SelectListGroup { Name = "Dev Team" };
    var group2 = new SelectListGroup { Name = "QA Team" };

    var employeeList = new List<SelectListItem>()
    {
        new SelectListItem() { Value = "1", Text = "Shyju", Group = group1 },
        new SelectListItem() { Value = "2", Text = "Bryan", Group = group1 },
        new SelectListItem() { Value = "3", Text = "Kevin", Group = group2 },
        new SelectListItem() { Value = "4", Text = "Alex", Group = group2 }
    };
    vm.Employees = employeeList;
    return View(vm);
}

Там нет никаких изменений в коде представления. помощник по тегу select теперь будет отображать параметры внутри 2 элементов optgroup.

Я создал интерфейс и <options> тег помощник для этого. Так что мне не пришлось конвертировать IEnumerable<T> предметы в IEnumerable<SelectListItem> каждый раз, когда мне нужно заполнить <select> контроль.

И я думаю, что это прекрасно работает...

Использование что-то вроде:

<select asp-for="EmployeeId">
    <option value="">Please select...</option>
    <options asp-items="@Model.EmployeesList" />
</select>

И чтобы заставить его работать с помощником тега, вы должны реализовать этот интерфейс в своем классе:

public class Employee : IIntegerListItem
{
   public int Id { get; set; }
   public string FullName { get; set; }

   public int Value { return Id; }
   public string Text{ return FullName ; }
}

Это необходимые коды:

Интерфейс:

public interface IIntegerListItem
{
    int Value { get; }
    string Text { get; }
}

<options> помощник по тегам:

[HtmlTargetElement("options", Attributes = "asp-items")]
public class OptionsTagHelper : TagHelper
{
    public OptionsTagHelper(IHtmlGenerator generator)
    {
        Generator = generator;
    }

    [HtmlAttributeNotBound]
    public IHtmlGenerator Generator { get; set; }

    [HtmlAttributeName("asp-items")]
    public object Items { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.SuppressOutput();
        // Is this <options /> element a child of a <select/> element the SelectTagHelper targeted?
        object formDataEntry;
        context.Items.TryGetValue(typeof(SelectTagHelper), out formDataEntry);

        var selectedValues = formDataEntry as ICollection<string>;
        var encodedValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
        if (selectedValues != null && selectedValues.Count != 0)
        {
            foreach (var selectedValue in selectedValues)
            {
                encodedValues.Add(Generator.Encode(selectedValue));
            }
        }

        IEnumerable<SelectListItem> items = null;
        if (Items != null)
        {
            if (Items is IEnumerable)
            {
                var enumerable = Items as IEnumerable;
                if (Items is IEnumerable<SelectListItem>)
                    items = Items as IEnumerable<SelectListItem>;
                else if (Items is IEnumerable<IIntegerListItem>)
                    items = ((IEnumerable<IIntegerListItem>)Items).Select(x => new SelectListItem() { Selected = false, Value = ((IIntegerListItem)x).Value.ToString(), Text = ((IIntegerListItem)x).Text });
                else
                    throw new InvalidOperationException(string.Format("The {2} was unable to provide metadata about '{1}' expression value '{3}' for <options>.",
                        "<options>",
                        "ForAttributeName",
                        nameof(IModelMetadataProvider),
                        "For.Name"));
            }
            else
            {
                throw new InvalidOperationException("Invalid items for <options>");
            }

            foreach (var item in items)
            {
                bool selected = (selectedValues != null && selectedValues.Contains(item.Value)) || encodedValues.Contains(item.Value);
                var selectedAttr = selected ? "selected='selected'" : "";

                if (item.Value != null)
                    output.Content.AppendHtml($"<option value='{item.Value}' {selectedAttr}>{item.Text}</option>");
                else
                    output.Content.AppendHtml($"<option>{item.Text}</option>");
            }
        }
    }
}

Там может быть некоторая опечатка, но цель ясна, я думаю. Мне пришлось немного отредактировать.

Мой ответ ниже не решает вопрос, но он относится к.

Если кто-то использует enum вместо модели класса, как в этом примере:

public enum Counter
{
    [Display(Name = "Number 1")]
    No1 = 1,
    [Display(Name = "Number 2")]
    No2 = 2,
    [Display(Name = "Number 3")]
    No3 = 3
}

И свойство для получения значения при отправке:

public int No { get; set; }

На странице бритвы, вы можете использовать Html.GetEnumSelectList<Counter>() чтобы получить свойства перечисления.

<select asp-for="No" asp-items="@Html.GetEnumSelectList<Counter>()"></select>

Он генерирует следующий HTML:

<select id="No" name="No">
    <option value="1">Number 1</option>
    <option value="2">Number 2</option>
    <option value="3">Number 3</option>
</select>

Вы также можете использовать IHtmlHelper.GetEnumSelectList.

    // Summary:
    //     Returns a select list for the given TEnum.
    //
    // Type parameters:
    //   TEnum:
    //     Type to generate a select list for.
    //
    // Returns:
    //     An System.Collections.Generic.IEnumerable`1 containing the select list for the
    //     given TEnum.
    //
    // Exceptions:
    //   T:System.ArgumentException:
    //     Thrown if TEnum is not an System.Enum or if it has a System.FlagsAttribute.
    IEnumerable<SelectListItem> GetEnumSelectList<TEnum>() where TEnum : struct;

Вы можете использовать код ниже для множественного выбора:

<select asp-for="EmployeeId"  multiple="multiple" asp-items="@ViewBag.Employees">
    <option>Please select</option>
</select>

Вы также можете использовать:

<select id="EmployeeId" name="EmployeeId"  multiple="multiple" asp-items="@ViewBag.Employees">
        <option>Please select</option>
    </select>

требуется некоторая коллекция экземпляров SelectListItemкласс (из пространства имен Microsoft.AspNetCore.Mvc.Rendering), который содержит Textа также Valueхарактеристики. Таким образом, вы можете преобразовать свою коллекцию сотрудников в требуемую таким образом. employees.Select(e => new SelectListItem(e.FullName, e.Id.ToString()))и положить результат в asp-itemsатрибут.

В Get:

public IActionResult Create()
{
    ViewData["Tags"] = new SelectList(_context.Tags, "Id", "Name");
    return View();
}

В сообщении:

var selectedIds= Request.Form["Tags"];

Ввиду:

<label>Tags</label>
<select  asp-for="Tags"  id="Tags" name="Tags" class="form-control" asp-items="ViewBag.Tags" multiple></select>
Другие вопросы по тегам