在ASP.NET Core MVC中选择Tag Helper

时间:2016-01-06 01:06:12

标签: c# asp.net-core asp.net-core-mvc tag-helpers

我需要一些帮助来解决ASP.NET Core中的select标记帮助程序。

我有一个员工列表,我正在尝试绑定到select标签帮助器。我的员工处于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="???" />

我很感激这方面的一些帮助。感谢。

6 个答案:

答案 0 :(得分:277)

使用选择标记帮助程序呈现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的{​​{1}}属性。

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名称空间。

确保为select元素使用显式结束标记。如果使用自闭合标记方法,标记帮助器将呈现一个空的SELECT元素!

以下方法无效

Microsoft.AspNet.Mvc.Rendering

但这会奏效。

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

使用实体框架从数据库表中获取数据

以上示例使用硬编码项目作为选项。所以我想我会添加一些示例代码来使用Entity框架来获取数据,因为很多人都使用它。

假设您的DbContext对象有一个名为<select asp-for="EmployeeId" asp-items="@Model.Employees"></select> 的属性,其类型为Employees,其中DbSet<Employee>实体类具有Employee和{{ 1}}像这样的属性

Id

您可以使用LINQ查询来获取员工,并使用LINQ表达式中的Select方法为每个员工创建Name个对象的列表。

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

假设SelectListItem是您的数据库上下文对象。视图代码与上面相同。

使用SelectList

有些人更喜欢使用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

现在,在您的GET操作中,您可以使用SelectList构造函数填充视图模型的public class MyViewModel { public int EmployeeId { get; set; } public SelectList Employees { set; get; } } 属性。确保您指定了SelectListEmployees参数。

dataValueField

这里我调用dataTextField方法来获取Employee对象列表,每个对象都有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对象的{1}}。您可以将硬编码列表更改为从数据库表中读取数据的代码。

视图代码相同。

DataValueField

从字符串列表中渲染SELECT元素。

有时您可能希望从字符串列表中呈现select元素。在这种情况下,您可以使用仅DataTextField

SelectList构造函数
<select asp-for="EmployeeId" asp-items="@Model.Employees" >
    <option>Please select one</option>
</select>

视图代码相同。

设置所选选项

有时,您可能希望将一个选项设置为SELECT元素中的默认选项(例如,在编辑屏幕中,您要加载以前保存的选项值)。为此,您只需将SelectList属性值设置为您要选择的选项的值。

IEnumerable<T>

这将在呈现页面时在select元素中选择Tom。

多选下拉列表

如果要渲染多选下拉列表,只需将视图中用于var vm = new MyViewModel(); var items = new List<string> {"Monday", "Tuesday", "Wednesday"}; vm.Employees = new SelectList(items); return View(vm); 属性的视图模型属性更改为数组类型。

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); } 属性的select元素呈现HTML标记,这将允许用户选择多个选项。

asp-for

在多选

中设置所选选项

与单选一样,将public class MyViewModel { public int[] EmployeeIds { get; set; } public List<SelectListItem> Employees { set; get; } } 属性值设置为您想要的值数组。

multiple

这将在渲染页面时在多选元素中选择Tom和Jerry选项。

使用ViewBag传输项目列表

如果您不希望保留集合类型属性以将选项列表传递给视图,则可以使用动态ViewBag来执行此操作。(这不是我个人推荐的方法,因为viewbag是动态的,您的代码容易出现无法捕获的拼写错误

@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

使用ViewBag传输项目列表并设置所选选项

与上述相同。您所要做的就是将属性(为其绑定下拉列表的值)设置为您要选择的选项的值。

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

并在视图中

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 tag helper方法支持下拉列表中的分组选项。您所要做的就是在操作方法中指定每个<select asp-for="EmployeeId" asp-items="@ViewBag.Employees"> <option>Please select one</option> </select> 的{​​{1}}属性值。

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标签帮助器现在将在2 optgroup个项目中呈现选项。

答案 1 :(得分:9)

我为此创建了一个Interface和一个<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>");
            }
        }
    }
}

可能会有一些错字但我认为目标很明确。我不得不编辑一下。

答案 2 :(得分:3)

您也可以使用 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;

答案 3 :(得分:1)

您可以使用以下代码进行多次选择

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

答案 4 :(得分: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>

答案 5 :(得分:0)

我在下面的回答不能不能解决问题,但它与相关

如果有人使用PartialView而不是类模型,例如以下示例:

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

它生成以下HTML:

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