内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用
我需要帮助ASP.NET Core中的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="???" />
使用Select Tag帮助器在视图中呈现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
属性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
属于Microsoft.AspNet.Mvc.Rendering
命名空间。
使用实体框架从数据库表中获取数据
以上示例正在使用硬编码项目作为选项。所以我想我会添加一些示例代码来获取使用实体框架的数据,因为很多人都使用它。
让我们假设你的DbContext对象有一个名为属性Employees
,它是类型DbSet<Employee>
,其中Employee
实体类有一个Id
和Name
属性这样的
public class Employee
{
public int Id { set; get; }
public string Name { set; get; }
}
可以使用linq查询来获取员工,并使用linq表达式中的Select方法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
你的数据库上下文对象。视图代码与上面相同。
使用SelectList
有些人更喜欢用SelectList
class来保存呈现选项所需的项目。
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()
{
return new List<Employee>
{
new Employee { Id=1, FirstName="Shyju"},
new Employee { Id=2, FirstName="Bryan"}
};
}
这里我调用的GetEmployees
方法来获取Employee对象的列表,每一个Id
和FirstName
属性,我使用这些属性DataValueField
和DataTextField
对的SelectList
,我们创建的对象。可以将硬编码列表更改为从数据库表中读取数据的代码。
视图代码将是相同的。
<select asp-for="EmployeeId" asp-items="@Model.Employees" >
<option>Please select one</option>
</select>
从字符串列表中呈现一个SELECT元素。
有时可能想要从字符串列表中呈现选择元素。在这种情况下,你可以使用SelectList
只需要的构造函数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);
}
这将在页面呈现时在select元素中选择Tom选项。
如果要渲染多选下拉列表,可以简单地将视图中用于视图属性的视图模型属性更改为asp-for
数组类型。
public class MyViewModel
{
public int[] EmployeeIds { get; set; }
public List<SelectListItem> Employees { set; get; }
}
这将使select元素的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和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>
选择标签帮助器方法支持下拉菜单中的分组选项。所要做的就是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项目内的选项。
我<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>");
}
}
}
}
可能有一些错字,但我认为目标很明确。我不得不编辑一点点。