Виберіть помічник тегів у ASP.NET Core MVC


162

Мені потрібна допомога з помічником Select tag в ASP.NET Core.

У мене є список працівників, яких я намагаюся прив’язати до помічника вибору тегів. Мої працівники знаходяться в 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; }
}

Моє запитання полягає в тому, як я можу своєму помічнику вибору тегу використовувати значення Idяк значення під час відображення FullNameу випадаючому списку?

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

Буду вдячний за допомогу в цьому. Дякую.


3
просто щось, що я думав, що я повинен додати, воно, здається, не працює, якщо ви закриєте тег вибору, негайно завжди закривайте теги з </select> помічником тегу не працював із <select asp-for ..... />
RoughPlace

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

Відповіді:


379

Використання помічників 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 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 це ваш контекст db. Код перегляду такий же, як і вище.

Використання 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()
{
    // hard coded list for demo. 
    // You may replace with real data from database to create Employee objects
    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 зі списку рядків.

Іноді, можливо, захочеться відтворити вибраний елемент зі списку рядків. У цьому випадку ви можете використовувати 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 у елементі вибору, коли сторінка надається.

Спадне меню "Вибір"

Якщо ви хочете вивести спад із декількома виборами, ви можете просто змінити властивість моделі перегляду, яку ви використовуєте для asp-forатрибута у вашому представленні, на тип масиву.

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

Це призведе до розмітки HTML для елемента вибору з 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 для цього. ( Це не мій персонально рекомендований підхід, оскільки панель перегляду динамічна, а ваш код схильний до незчитування помилки друку )

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>

Використання ViewBag для передачі списку елементів та налаштування вибраної опції

Це те саме, що вище. Все, що вам потрібно зробити, - встановити значення властивості (для якого ви прив'язуєте спадне меню) до значення параметра, яке ви хочете вибрати.

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

    vm.EmployeeId = 2;  // This will set Bryan as selected

    return View(new MyViewModel());
}

і на виду

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

Групування предметів

Метод помічника виділення тегів підтримує параметри групування у спадному меню. Все, що вам потрібно зробити, це вказати 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);
}

Код перегляду не змінюється. Вибрати допоміжний тег тепер буде надавати опції всередині 2 OPTGROUP пунктів.


1
Дякую! Наче подібний старому синтаксису бритви, де нам потрібно здійснити перетворення у SelectList. Знову дякую.
Сем

7
Я шукав, як додати порожній варіант, дякую за використання<option>Please select one</option>
Serj Sagan

5
Зауважте, що у вас ОБОВ'ЯЗКОВО бути тег закриття </select> - він не працюватиме, якщо ви спробуєте самостійно закрити тег вибору, як <select ... />. Крім того, якщо ви використовуєте порожню опцію типу "Будь ласка, виберіть", вам потрібно надати їй значення порожнього рядка "" для того, щоб необхідна перевірка поля працювала.
Енді

3
"Переконайтеся, що ви використовуєте явний закриваючий тег для елемента вибору. Якщо ви використовуєте підхід самозакриваючого тегу, помічник тегу видасть порожній елемент SELECT!" Це було питання в моєму випадку. Ура!
Маріуш

2
Дякуємо, що доклали стільки зусиль до цієї відповіді!
Відар

11

Я створив інтерфейс і <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>");
            }
        }
    }
}

Може бути певний помилок, але мета чітка, я думаю. Довелося трохи відредагувати.


4

Ви також можете використовувати 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;

4

Моя відповідь нижче не вирішує питання, але це стосується .

Якщо хтось використовує 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>

3

Ви можете використовувати код нижче для декількох виборів :

<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>

0

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