webentwicklung-frage-antwort-db.com.de

Wählen Sie in ASP.NET Core MVC Tag Helper aus

Ich brauche Hilfe beim select-Tag-Helfer in ASP.NET Core.

Ich habe eine Liste von Mitarbeitern, die ich an einen ausgewählten Tag-Helfer binden möchte. Meine Mitarbeiter befinden sich in einem List<Employee> EmployeesList und der ausgewählte Wert wird in die EmployeeId-Eigenschaft übernommen. Mein Ansichtsmodell sieht folgendermaßen aus:

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

Meine Mitarbeiterklasse sieht so aus:

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

Meine Frage ist, wie kann ich meinem select-Tag-Helfer sagen, dass er die Id als Wert verwendet, während FullName in der Dropdown-Liste angezeigt wird?

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

Ich würde mich über etwas Hilfe freuen. Vielen Dank.

103
Sam

Verwenden der Hilfe zum Auswählen eines Tags zum Rendern eines SELECT-Elements

Erstellen Sie in Ihrer GET-Aktion ein Objekt Ihres Ansichtsmodells, laden Sie die Auflistungseigenschaft EmployeeList und senden Sie diese an die Ansicht.

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

Erstellen Sie in Ihrer Erstellungsansicht ein neues SelectList-Objekt aus der EmployeeList-Eigenschaft, und übergeben Sie dieses als Wert für die asp-items-Eigenschaft.

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

Und Ihre HttpPost-Aktionsmethode, um die übermittelten Formulardaten zu akzeptieren.

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

Oder

Wenn Ihr Ansichtsmodell einen List<SelectListItem> als Eigenschaft für Ihre Dropdown-Elemente hat.

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

Und in Ihrer Get Action,

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

In der Ansicht können Sie die Employees-Eigenschaft direkt für den asp-items verwenden.

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

Die Klasse SelectListItem gehört zum Microsoft.AspNet.Mvc.Rendering-Namespace.

Stellen Sie sicher, dass Sie ein explizites schließendes Tag für das select-Element verwenden. Wenn Sie den selbstschließenden Tag-Ansatz verwenden, rendert der Tag-Helfer ein leeres SELECT-Element!

Der folgende Ansatz funktioniert nicht

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

Aber das wird funktionieren.

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

Abrufen von Daten aus der Datenbanktabelle mithilfe des Entitätsframeworks

In den obigen Beispielen werden für die Optionen hartcodierte Elemente verwendet. Also dachte ich, ich werde ein paar Beispielcodes hinzufügen, um Daten mit dem Entity-Framework zu erhalten, da viele Leute das verwenden.

Nehmen wir an, Ihr DbContext-Objekt hat eine Eigenschaft namens Employees, die vom Typ DbSet<Employee> ist, wobei die Employee-Entitätsklasse eine Id- und Name-Eigenschaft wie diese hat

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

Sie können eine LINQ-Abfrage verwenden, um die Mitarbeiter abzurufen, und die Select-Methode in Ihrem LINQ-Ausdruck verwenden, um eine Liste von SelectListItem-Objekten für jeden Mitarbeiter zu erstellen.

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

Angenommen, context ist Ihr Datenbankkontextobjekt. Der Ansichtscode ist derselbe wie oben.

SelectList verwenden

Einige Leute ziehen es vor, die Klasse SelectList zu verwenden, um die Elemente zu speichern, die zum Rendern der Optionen benötigt werden.

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

In Ihrer GET-Aktion können Sie jetzt den Konstruktor SelectList verwenden, um die Employees-Eigenschaft des Ansichtsmodells aufzufüllen. Stellen Sie sicher, dass Sie die Parameter dataValueField und dataTextField angeben.

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

Hier rufe ich die GetEmployees-Methode auf, um eine Liste von Employee-Objekten mit jeweils einer Id- und FirstName-Eigenschaft abzurufen, und ich verwende diese Eigenschaften als DataValueField und DataTextField des von uns erstellten SelectList-Objekts. Sie können die hartcodierte Liste in einen Code ändern, der Daten aus einer Datenbanktabelle liest.

Der Ansichtscode ist derselbe.

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

Rendern Sie ein SELECT-Element aus einer Liste von Strings.

Manchmal möchten Sie ein Auswahlelement aus einer Liste von Strings rendern. In diesem Fall können Sie den Konstruktor SelectList verwenden, der nur IEnumerable<T> verwendet.

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

Der Ansichtscode ist derselbe.

Ausgewählte Optionen einstellen

In einigen Fällen möchten Sie möglicherweise eine Option als Standardoption im SELECT-Element festlegen (z. B. möchten Sie in einem Bearbeitungsbildschirm den zuvor gespeicherten Optionswert laden). Dazu können Sie den Eigenschaftswert EmployeeId einfach auf den Wert der Option setzen, die Sie auswählen möchten.

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

Dadurch wird die Option Tom im select-Element ausgewählt, wenn die Seite gerendert wird.

Mehrfachauswahl Dropdown

Wenn Sie ein Multi-Select-Dropdown-Menü rendern möchten, können Sie einfach Ihre Ansichtsmodelleigenschaft, die Sie für das asp-for-Attribut in Ihrer Ansicht verwenden, in einen Array-Typ ändern.

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

Dadurch wird das HTML-Markup für das select-Element mit dem Attribut multiple gerendert, wodurch der Benutzer mehrere Optionen auswählen kann.

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

Ausgewählte Optionen in der Mehrfachauswahl einstellen

Stellen Sie den Wert der EmployeeIds-Eigenschaft ähnlich wie bei der Einzelauswahl auf ein Array mit gewünschten Werten ein.

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

Dadurch wird beim Rendern der Seite die Option Tom und Jerry im Multi-Select-Element ausgewählt.

Verwenden von ViewBag zum Übertragen der Liste der Elemente

Wenn Sie es nicht vorziehen, eine Auflistungstyp-Eigenschaft beizubehalten, um die Liste der Optionen an die Ansicht zu übergeben, können Sie dies mit dem dynamischen ViewBag tun. (Dies ist kein persönlich empfohlener Ansatz, da viewbag dynamisch ist und Ihr Code dynamisch ist anfällig für ungetippte Tippfehler)

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

und in der Ansicht

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

Verwenden von ViewBag zum Übertragen der Liste der Elemente und Einstellen der ausgewählten Option

Es ist dasselbe wie oben. Sie müssen nur den Wert der Eigenschaft (für die Sie die Dropdown-Liste binden) auf den Wert der Option setzen, die Sie auswählen möchten.

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

und in der Ansicht

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

Elemente gruppieren

Die Hilfsmethode select tag unterstützt Gruppierungsoptionen in einer Dropdown-Liste. Alles, was Sie tun müssen, ist, den Group-Eigenschaftswert jeder SelectListItem in Ihrer Aktionsmethode anzugeben.

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

Der Ansichtscode wird nicht geändert. Der Helper für das Auswahl-Tag rendert nun die Optionen innerhalb von 2 optgroup items.

245
Shyju

Ich habe dazu ein Interface und einen <options>-Tag-Helfer erstellt. Daher musste ich die IEnumerable<T>-Elemente nicht jedes Mal in IEnumerable<SelectListItem> konvertieren, wenn ich das <select>-Steuerelement auffüllen muss.

Und ich denke es funktioniert wunderbar ...

Die Verwendung ist so etwas wie:

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

Und damit es mit dem Tag-Helfer funktioniert, müssen Sie diese Schnittstelle in Ihrer Klasse implementieren:

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

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

Dies sind die benötigten Codes:

Die Schnittstelle:

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

Der <options>-Tag-Helfer:

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

Es kann Tippfehler geben, aber das Ziel ist klar, denke ich. Ich musste ein bisschen bearbeiten.

9
Yves

Sie können auch IHtmlHelper.GetEnumSelectList verwenden.

    // 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;
3
Amir Rezaei

sie können den Code für multiple select verwenden:

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

sie können auch verwenden:

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

In Get:

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

In der Post:

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

Im Hinblick auf :

<label>Tags</label>
<select  asp-for="Tags"  id="Tags" name="Tags" class="form-control" asp-items="ViewBag.Tags" multiple></select>
0
Anas Al-Qudah

Meine Antwort unten nicht löst die Frage, aber sie bezieht sich auf.

Wenn jemand enum anstelle eines Klassenmodells verwendet, wie im folgenden Beispiel:

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

Und eine Eigenschaft, um den Wert beim Einreichen zu erhalten:

public int No { get; set; }

Auf der Rasiermesserseite können Sie Html.GetEnumSelectList<Counter>() verwenden, um die Aufzählungseigenschaften abzurufen.

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

Es generiert den folgenden HTML-Code:

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