Wybierz pomocnika tagów w ASP.NET Core MVC

162

Potrzebuję pomocy dotyczącej pomocnika wyboru tagów w ASP.NET Core.

Mam listę pracowników, których próbuję powiązać z pomocnikiem do wybierania tagów. Moi pracownicy są w stanie List<Employee> EmployeesListi wybrana wartość trafi do EmployeeIdnieruchomości. Mój model widoku wygląda następująco:

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

Moja klasa pracownicza wygląda następująco:

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

Moje pytanie brzmi: jak mam powiedzieć mojemu pomocnikowi tagów wyboru, aby używał Idjako wartości podczas wyświetlania FullNamena liście rozwijanej?

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

Byłbym wdzięczny za pomoc w tym. Dzięki.

Sam
źródło
3
tylko coś, co pomyślałem, że powinienem dodać, wygląda na to, że nie działa, jeśli natychmiast zamkniesz tag zaznaczania, zawsze zamykaj tagi za pomocą </select> pomocnik tagów nie działał z <select asp-for ..... />
RoughPlace
tylko wskazówka. Sterowniki rusztowań pokazują ogólnie najlepsze sposoby na takie rzeczy
Neville Nazerane

Odpowiedzi:

379

Używanie pomocników Select Tag do renderowania elementu SELECT

W akcji GET utwórz obiekt swojego modelu widoku, załaduj EmployeeListwłaściwość kolekcji i wyślij ją do widoku.

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);
}

W widoku tworzenia utwórz nowy SelectListobiekt z EmployeeListwłaściwości i przekaż go jako wartość asp-itemswłaściwości.

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

Oraz metodę akcji HttpPost, aby zaakceptować przesłane dane formularza.

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

Lub

Jeśli Twój model widoku ma List<SelectListItem>właściwość elementów listy rozwijanej.

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

A w twojej akcji 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);
}

W widoku możesz bezpośrednio użyć Employeeswłaściwości dla 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>

Klasa SelectListItemnależy do Microsoft.AspNet.Mvc.Renderingprzestrzeni nazw.

Upewnij się, że używasz wyraźnego tagu zamykającego dla elementu select. Jeśli używasz samozamykającego się tagu, pomocnik tagu wyrenderuje pusty element SELECT!

Poniższe podejście nie zadziała

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

Ale to zadziała.

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

Pobieranie danych z tabeli bazy danych przy użyciu struktury encji

Powyższe przykłady używają elementów zakodowanych na stałe dla opcji. Pomyślałem więc, że dodam przykładowy kod, aby uzyskać dane za pomocą frameworka Entity, ponieważ wiele osób z niego korzysta.

Załóżmy, że Twój obiekt DbContext ma właściwość o nazwie Employees, która jest typu, w DbSet<Employee>którym Employeeklasa jednostki ma właściwość Idi Nametaką jak ta

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

Możesz użyć zapytania LINQ, aby pobrać pracowników i użyć metody Select w wyrażeniu LINQ, aby utworzyć listę SelectListItemobiektów dla każdego pracownika.

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);
}

Zakładając, że contextjest to obiekt kontekstu db. Kod widoku jest taki sam jak powyżej.

Korzystanie z SelectList

Niektórzy wolą używać SelectListklasy do przechowywania elementów potrzebnych do renderowania opcji.

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

Teraz w akcji GET możesz użyć SelectListkonstruktora do wypełnienia Employeeswłaściwości modelu widoku. Upewnij się, że określasz parametry dataValueFieldi 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" }
    };
}

Ja tu wywołanie GetEmployeesmetody, aby uzyskać listę obiektów pracownicze, każdy z Idi FirstNamemienia i używam tych właściwości, jak DataValueFieldi DataTextFieldna SelectListobiekcie stworzyliśmy. Możesz zmienić zakodowaną listę na kod, który odczytuje dane z tabeli bazy danych.

Kod widoku będzie taki sam.

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

Renderuj element SELECT z listy ciągów.

Czasami możesz chcieć wyrenderować wybrany element z listy ciągów. W takim przypadku możesz użyć SelectListkonstruktora, który zajmuje tylko plikiIEnumerable<T>

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

Kod widoku będzie taki sam.

Ustawianie wybranych opcji

Czasami możesz chcieć ustawić jedną opcję jako opcję domyślną w elemencie SELECT (na przykład na ekranie edycji chcesz załadować poprzednio zapisaną wartość opcji). Aby to zrobić, możesz po prostu ustawić EmployeeIdwartość właściwości na wartość opcji, którą chcesz wybrać.

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);
}

Spowoduje to wybranie opcji Tom w elemencie select, gdy strona jest renderowana.

Lista rozwijana wielokrotnego wyboru

Jeśli chcesz renderować listę rozwijaną wielokrotnego wyboru, możesz po prostu zmienić właściwość modelu widoku, której używasz dla asp-foratrybutu w widoku, na typ tablicy.

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

Spowoduje to renderowanie znaczników HTML dla elementu select z multipleatrybutem, który pozwoli użytkownikowi wybrać wiele opcji.

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

Ustawianie wybranych opcji w trybie wielokrotnego wyboru

Podobnie jak w przypadku wyboru pojedynczego, ustaw EmployeeIdswartość właściwości na tablicę żądanych wartości.

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);
}

Spowoduje to wybranie opcji Tom i Jerry w elemencie wielokrotnego wyboru podczas renderowania strony.

Używanie ViewBag do przesyłania listy elementów

Jeśli nie wolisz zachować właściwości typu kolekcji, aby przekazać listę opcji do widoku, możesz użyć dynamicznego ViewBag, aby to zrobić ( nie jest to moje osobiście zalecane podejście, ponieważ obszar widoku jest dynamiczny, a kod jest podatny na literówki )

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

i w widoku

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

Używanie ViewBag do przenoszenia listy elementów i ustawiania wybranej opcji

Tak samo jak powyżej. Wszystko, co musisz zrobić, to ustawić wartość właściwości (dla której wiążesz listę rozwijaną) na wartość opcji, którą chcesz wybrać.

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());
}

i w widoku

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

Grupowanie elementów

Metoda pomocnika wyboru tagów obsługuje opcje grupowania w menu rozwijanym. Wszystko, co musisz zrobić, to określić Groupwartość właściwości każdego z nich SelectListItemw swojej metodzie akcji.

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);
}

Nie ma zmian w kodzie widoku. pomocnik tagów wyboru będzie teraz renderował opcje wewnątrz 2 elementów optgroup .

Shyju
źródło
1
Dziękuję Ci! Coś jak stara składnia maszynki do golenia, w której musimy wykonać konwersję do SelectList. Dzięki jeszcze raz.
Sam
7
Szukałem, jak dodać pustą opcję, dzięki za użycie<option>Please select one</option>
Serj Sagan
5
Zwróć uwagę, że MUSISZ mieć tag zamykający </select> - nie zadziała, jeśli spróbujesz samodzielnie zamknąć tag zaznaczania, np. <Select ... />. Ponadto, jeśli używasz pustej opcji, takiej jak „Wybierz jeden”, musisz nadać jej wartość pustego ciągu „”, aby wymagane sprawdzenie poprawności pola działało.
Andy
3
"Upewnij się, że używasz jawnego tagu zamykającego dla elementu select. Jeśli używasz metody samozamykającego tagu, pomocnik tagu wyrenderuje pusty element SELECT!" To był problem w moim przypadku. Twoje zdrowie!
Mariusz
2
Dziękujemy za włożenie tak dużego wysiłku w tę odpowiedź!
Vidar,
11

Stworzyłem do tego interfejs i <options>pomocnika tagów. Nie musiałem więc konwertować IEnumerable<T>elementów na za IEnumerable<SelectListItem>każdym razem, gdy muszę wypełnić <select>formant.

I myślę, że działa pięknie ...

Użycie jest takie jak:

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

Aby działało z pomocnikiem tagów, musisz zaimplementować ten interfejs w swojej klasie:

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

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

Oto potrzebne kody:

Interfejs:

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

<options>Tag pomocnika:

[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>");
            }
        }
    }
}

Może być pewna literówka, ale myślę, że cel jest jasny. Musiałem trochę edytować.

Yves
źródło
4

Możesz również użyć 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;
Amir Rezaei
źródło
4

Moja odpowiedź poniżej nie rozwiązuje pytania, ale dotyczy .

Jeśli ktoś używa enumzamiast modelu klasy, na przykład:

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

Oraz właściwość do pobrania wartości podczas przesyłania:

public int No { get; set; }

Na stronie maszynki do golenia możesz użyć, Html.GetEnumSelectList<Counter>()aby uzyskać właściwości wyliczenia.

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

Generuje następujący kod 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>
Dębnik
źródło
3

Możesz użyć poniższego kodu do wielokrotnego wyboru :

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

Możesz także użyć:

<select id="EmployeeId" name="EmployeeId"  multiple="multiple" asp-items="@ViewBag.Employees">
    <option>Please select</option>
</select>
Zubayer Bin Ayub
źródło
0

W Get:

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

W poście:

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

Z uwagi :

<label>Tags</label>
<select  asp-for="Tags"  id="Tags" name="Tags" class="form-control" asp-items="ViewBag.Tags" multiple></select>
Anas Al-Qudah
źródło