เลือก Tag Helper ใน ASP.NET Core MVC


162

ฉันต้องการความช่วยเหลือเกี่ยวกับตัวเลือกแท็กตัวช่วยใน 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

การใช้ตัวช่วยเลือกแท็กเพื่อสร้างองค์ประกอบที่เลือก

ในการดำเนินการ 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);
}

และในมุมมองของคุณโดยตรงสามารถใช้สถานที่ให้บริการสำหรับEmployeesasp-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 เพื่อรับพนักงานและใช้วิธีเลือกในนิพจน์ 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วิธีการที่จะได้รับรายชื่อของวัตถุของพนักงานแต่ละคนที่มีIdและFirstNameคุณสมบัติและฉันจะใช้คุณสมบัติเหล่านั้นDataValueFieldและDataTextFieldของSelectListวัตถุที่เราสร้างขึ้น คุณสามารถเปลี่ยนรายการ hardcoded เป็นรหัสที่อ่านข้อมูลจากตารางฐานข้อมูล

รหัสการดูจะเหมือนกัน

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

แสดงองค์ประกอบ SELECT จากรายการสตริง

บางครั้งคุณอาจต้องการแสดงองค์ประกอบที่เลือกจากรายการสตริง ในกรณีนี้คุณสามารถใช้SelectListConstructor ที่ใช้เวลาเท่านั้น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);
}

สิ่งนี้จะเลือกตัวเลือก Tom and Jerry ในองค์ประกอบเลือกหลายตัวเมื่อมีการแสดงหน้าเว็บ

ใช้ 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>

ใช้ 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 ขอบคุณอีกครั้ง.
Sam

7
ฉันกำลังมองหาวิธีเพิ่มตัวเลือกที่ว่างเปล่าขอบคุณที่ใช้<option>Please select one</option>
Serj Sagan

5
โปรดทราบว่าคุณต้องมีแท็กปิด </select> - จะไม่ทำงานหากคุณพยายามปิดแท็กที่เลือกเช่น <select ... /> นอกจากนี้หากคุณใช้ตัวเลือกที่ว่างเปล่าเช่น "โปรดเลือกหนึ่งตัว" คุณจะต้องให้ค่าสตริงว่าง "" เพื่อให้การตรวจสอบฟิลด์ที่ต้องการใช้งานได้
Andy

3
"ตรวจสอบให้แน่ใจว่าคุณกำลังใช้แท็กปิดที่ชัดเจนสำหรับองค์ประกอบที่เลือกถ้าคุณใช้วิธีการปิดแท็กด้วยตนเองตัวช่วยแท็กจะแสดงองค์ประกอบที่ว่างเปล่า!" นี่เป็นปัญหาในกรณีของฉัน ไชโย!
Mariusz

2
ขอขอบคุณสำหรับการวางความพยายามมากลงไปในคำตอบนี้!
Vidar

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>()เพื่อรับคุณสมบัติ enum

<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

ในการรับ:

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>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.