Chọn Trình trợ giúp thẻ trong ASP.NET Core MVC


162

Tôi cần một số trợ giúp với trình trợ giúp thẻ chọn trong ASP.NET Core.

Tôi có một danh sách các nhân viên mà tôi đang cố gắng liên kết với một người trợ giúp thẻ chọn. Nhân viên của tôi đang ở trong một List<Employee> EmployeesListvà giá trị được lựa chọn sẽ đi vào EmployeeIdtài sản. Mô hình xem của tôi trông như thế này:

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

Lớp nhân viên của tôi trông như thế này:

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

Câu hỏi của tôi là làm thế nào để tôi nói với người trợ giúp thẻ chọn của tôi sử dụng Idlàm giá trị trong khi hiển thị FullNametrong danh sách thả xuống?

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

Tôi đánh giá cao sự giúp đỡ với điều này. Cảm ơn.


3
chỉ cần một cái gì đó tôi nghĩ rằng tôi nên thêm, nó dường như không hoạt động nếu bạn đóng thẻ chọn ngay lập tức luôn đóng các thẻ bằng </ select> trình trợ giúp thẻ không hoạt động với <select asp-for ..... />
RoughPlace

chỉ là một mẹo. Trình điều khiển giàn giáo hiển thị thường cho bạn thấy những cách tốt nhất cho những thứ như vậy
Neville Nazerane

Câu trả lời:


379

Sử dụng trình trợ giúp Chọn thẻ để hiển thị phần tử CHỌN

Trong hành động GET của bạn, tạo một đối tượng của mô hình khung nhìn của bạn, tải thuộc tính EmployeeListbộ sưu tập và gửi nó đến khung nhìn.

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

Và trong chế độ tạo của bạn, tạo một SelectListđối tượng mới từ thuộc EmployeeListtính và chuyển giá trị đó làm giá trị cho thuộc asp-itemstính.

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

Và phương thức hành động HttpPost của bạn để chấp nhận dữ liệu biểu mẫu đã gửi.

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

Hoặc là

Nếu mô hình xem của bạn có một List<SelectListItem>thuộc tính cho các mục thả xuống của bạn.

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

Và trong hành động nhận được của bạn,

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

Và trong chế độ xem, bạn có thể trực tiếp sử dụng Employeestài sản cho 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>

Lớp SelectListItemthuộc về Microsoft.AspNet.Mvc.Renderingkhông gian tên.

Hãy chắc chắn rằng bạn đang sử dụng thẻ đóng rõ ràng cho phần tử chọn. Nếu bạn sử dụng phương pháp tiếp cận thẻ tự đóng, trình trợ giúp thẻ sẽ hiển thị phần tử CHỌN trống!

Cách tiếp cận dưới đây sẽ không hoạt động

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

Nhưng điều này sẽ làm việc.

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

Lấy dữ liệu từ bảng cơ sở dữ liệu của bạn bằng khung thực thể

Các ví dụ trên đang sử dụng các mục được mã hóa cứng cho các tùy chọn. Vì vậy, tôi nghĩ rằng tôi sẽ thêm một số mã mẫu để lấy dữ liệu bằng khung Entity vì nhiều người sử dụng nó.

Giả sử đối tượng DbContext của bạn có một thuộc tính được gọi Employees, thuộc loại DbSet<Employee>Employeelớp thực thể có Idvà thuộc Nametính như thế này

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

Bạn có thể sử dụng truy vấn LINQ để nhận nhân viên và sử dụng phương thức Chọn trong biểu thức LINQ của bạn để tạo danh sách các SelectListItemđối tượng cho mỗi nhân viên.

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

Giả sử contextlà đối tượng bối cảnh db của bạn. Mã xem giống như trên.

Sử dụng Chọn danh sách

Một số người thích sử dụng SelectListlớp để giữ các mục cần thiết để hiển thị các tùy chọn.

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

Bây giờ trong hành động GET của bạn, bạn có thể sử dụng hàm SelectListtạo để điền vào thuộc Employeestính của mô hình khung nhìn. Hãy chắc chắn rằng bạn đang chỉ định dataValueFielddataTextFieldcác tham số.

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

Ở đây tôi đang gọi GetEmployeesphương thức để lấy danh sách các đối tượng Nhân viên, mỗi đối tượng có một Idvà thuộc FirstNametính và tôi sử dụng các thuộc tính đó như DataValueFieldDataTextFieldcủa SelectListđối tượng chúng ta đã tạo. Bạn có thể thay đổi danh sách mã hóa cứng thành mã đọc dữ liệu từ bảng cơ sở dữ liệu.

Mã xem sẽ giống nhau.

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

Kết xuất phần tử CHỌN từ danh sách các chuỗi.

Đôi khi bạn có thể muốn kết xuất một phần tử được chọn từ danh sách các chuỗi. Trong trường hợp đó, bạn có thể sử dụng hàm SelectListtạo chỉ mấtIEnumerable<T>

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

Mã xem sẽ giống nhau.

Đặt tùy chọn đã chọn

Đôi khi, bạn có thể muốn đặt một tùy chọn làm tùy chọn mặc định trong phần tử CHỌN (Ví dụ: trong màn hình chỉnh sửa, bạn muốn tải giá trị tùy chọn đã lưu trước đó). Để làm điều đó, bạn có thể chỉ cần đặt EmployeeIdgiá trị thuộc tính thành giá trị của tùy chọn bạn muốn được chọn.

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

Điều này sẽ chọn tùy chọn Tom trong phần tử chọn khi trang được hiển thị.

Thả xuống nhiều lựa chọn

Nếu bạn muốn hiển thị danh sách thả xuống đa lựa chọn, bạn chỉ cần thay đổi asp-forthuộc tính mô hình chế độ xem mà bạn sử dụng cho thuộc tính trong chế độ xem thành loại mảng.

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

Điều này sẽ hiển thị đánh dấu HTML cho phần tử chọn với multiplethuộc tính cho phép người dùng chọn nhiều tùy chọn.

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

Đặt tùy chọn đã chọn trong đa lựa chọn

Tương tự như chọn đơn, đặt EmployeeIdsgiá trị thuộc tính thành một mảng các giá trị bạn muốn.

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

Điều này sẽ chọn tùy chọn Tom và Jerry trong phần tử đa lựa chọn khi trang được hiển thị.

Sử dụng ViewBag để chuyển danh sách các mục

Nếu bạn không muốn giữ thuộc tính loại bộ sưu tập để chuyển danh sách các tùy chọn cho chế độ xem, bạn có thể sử dụng ViewBag động để làm như vậy ( Đây không phải là cách tiếp cận được đề xuất của cá nhân tôi vì viewbag là động và mã của bạn dễ bị hủy lỗi đánh máy )

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

và trong quan điểm

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

Sử dụng ViewBag để chuyển danh sách các mục và cài đặt tùy chọn đã chọn

Nó cũng giống như trên. Tất cả bạn phải làm là, đặt giá trị thuộc tính (mà bạn đang ràng buộc giá trị thả xuống) thành giá trị của tùy chọn bạn muốn được chọn.

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

và trong quan điểm

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

Nhóm các mục

Phương thức trình trợ giúp thẻ chọn hỗ trợ các tùy chọn nhóm trong danh sách thả xuống. Tất cả bạn phải làm là, chỉ định Groupgiá trị thuộc tính của từng SelectListItemtrong phương thức hành động của bạn.

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

Không có thay đổi trong mã xem. trình trợ giúp thẻ chọn bây giờ sẽ hiển thị các tùy chọn bên trong 2 mục optgroup .


1
Cảm ơn bạn! Kiểu như cú pháp dao cạo cũ mà chúng ta cần thực hiện chuyển đổi sang Chọn Danh sách. Cảm ơn một lần nữa.
Sam

7
Tôi đang tìm cách thêm một tùy chọn trống, cảm ơn vì đã sử dụng<option>Please select one</option>
Serj Sagan

5
Lưu ý rằng bạn PHẢI có thẻ đóng </ select> - nó sẽ không hoạt động nếu bạn cố tự đóng thẻ chọn như <select ... />. Ngoài ra, nếu bạn sử dụng một tùy chọn trống như "Vui lòng chọn một", bạn cần cung cấp cho nó một giá trị của chuỗi trống "" để xác thực trường bắt buộc hoạt động.
Andy

3
"Hãy chắc chắn rằng bạn đang sử dụng thẻ đóng rõ ràng cho phần tử chọn. Nếu bạn sử dụng phương pháp tiếp cận thẻ tự đóng, trình trợ giúp thẻ sẽ hiển thị phần tử CHỌN trống!" Đây là vấn đề trong trường hợp của tôi. Chúc mừng!
Mariusz

2
Cảm ơn bạn đã nỗ lực rất nhiều vào câu trả lời này!
Vidar

11

Tôi đã tạo một Giao diện và một trình <options>trợ giúp thẻ cho việc này. Vì vậy, tôi đã không phải chuyển đổi các IEnumerable<T>mục thành IEnumerable<SelectListItem>mỗi lần tôi phải đưa vào <select>điều khiển.

Và tôi nghĩ rằng nó hoạt động rất đẹp ...

Cách sử dụng là một cái gì đó như:

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

Và để làm cho nó hoạt động với trình trợ giúp thẻ, bạn phải triển khai giao diện đó trong lớp của mình:

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

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

Đây là các mã cần thiết:

Giao diện:

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

Trình <options>trợ giúp thẻ:

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

Có thể có một số lỗi đánh máy nhưng mục tiêu là rõ ràng tôi nghĩ. Tôi đã phải chỉnh sửa một chút.


4

Bạn cũng có thể sử dụng 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

Câu trả lời của tôi dưới đây không giải quyết được câu hỏi nhưng nó liên quan đến.

Nếu ai đó đang sử dụng enumthay vì một mô hình lớp, như ví dụ này:

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

Và một tài sản để có được giá trị khi gửi:

public int No { get; set; }

Trong trang dao cạo, bạn có thể sử dụng Html.GetEnumSelectList<Counter>()để lấy thuộc tính enum.

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

Nó tạo ra HTML sau:

<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

Bạn có thể sử dụng mã dưới đây cho nhiều lựa chọn :

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

Bạn cũng có thể dùng:

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

0

Trong Nhận:

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

Trong bài viết:

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

Trong chế độ xem:

<label>Tags</label>
<select  asp-for="Tags"  id="Tags" name="Tags" class="form-control" asp-items="ViewBag.Tags" multiple></select>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.