我在Razor视图的下拉列表中有一个项目列表。在数据库中,每个项目都有3个与之关联的值 - 数据库ID,短名称(用于显示)和长名称(用于传递给服务)。下拉列表必须显示短名称,因此我填充下拉列表,其中数据库ID为值,短名称为文本。
然而,当用户选择一个项目时,我需要将长名称作为查询参数传递给使用jQuery的搜索服务,例如当选择Cortina时,需要将“Ford Cortina 1979 Blue”传递给该服务。我的第一个想法是将长名称存储为数据短划线属性,但我想知道是否有更好的方法。所以
DB:
CARID SHORT_NAME LONG_NAME
1 Viper Dodge Viper 1982
2 Boxster Porsche Boxster 2009 Black
3 Cortina Ford Cortina 1979 Blue
控制器助手创建下拉列表:
public static IEnumerable<SelectListItem> GetSelectList(this IEFRepository repository, string typeName)
{
var vehicle = repository.TypeTypes.FirstOrDefault(t => t.Name.ToUpper() == typeName);
if (vehicle != null)
{
var carList = vehicle.SubTypes.ToList().OrderBy(s => s.Name);
var selectList = new SelectList(subTypeList, "SubTypeID", "Name");
return selectList;
}
}
以下是我用来创建下拉列表的代码:
<div class="editor-field">
@Html.DropDownListFor(model => model.CarID,
new SelectList(ViewBag.Cars, "Value", "Text", "1"))
@Html.ValidationMessageFor(model => model.CarShortName)
</div>
这是输出:
<select id="CarID" name="CarID" data-val="true" data-val-number="The field CarID must be a number." data-val-required="The CarID field is required.">
<option value="2">Boxster</option>
<option value="3">Cortina</option>
<option selected="selected" value="1">Viper</option>
</select>
答案 0 :(得分:23)
每个人都忘记了解决这些问题的“经典”方法:使用foreach
循环并实际编写输入html。唯一的缺点是你必须添加自动属性的东西(比如验证等),这取决于你的目的可能不是什么大问题。
类似的东西:
<select> // add other attributes as expected
@foreach(var type in Model.MyFancyTypes) {
<option value="@type.SubTypeID" data-description="@type.Description"
@if(ViewBag.TypeSelected == type.SubTypeID) {
selected="selected"
}>@type.Name</option>
}
</select>
答案 1 :(得分:21)
我有类似的情况,我需要将第三个值传递给每个列表项,以确定要在jQuery函数中执行的操作。这是我的解决方案(允许您在下拉列表中为每个项目添加任意数量的属性):
首先,我创建了一个SelectListItemWithAttributes类,如下所示:
public class SelectListItemWithAttributes : SelectListItem {
public IDictionary<string, string> HtmlAttributes { get; set; }
}
这允许我为选择列表创建项目,并附加额外的属性。
其次,我创建了一个名为DropDownListWithItemAttributesFor的HTML辅助方法,如下所示:
public static MvcHtmlString DropDownListWithItemAttributesFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TValue>> expression, IEnumerable<SelectListItemWithAttributes> selectList) {
string name = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(ExpressionHelper.GetExpressionText(expression));
var selectDoc = XDocument.Parse(htmlHelper.DropDownList(name, (IEnumerable<SelectListItem>)selectList).ToString());
var options = from XElement el in selectDoc.Element("select").Descendants()
select el;
for (int i = 0; i < options.Count(); i++){
var option = options.ElementAt(i);
var attributes = selectList.ElementAt(i);
foreach (var attribute in attributes.HtmlAttributes){
option.SetAttributeValue(attribute.Key, attribute.Value);
}
}
selectDoc.Root.ReplaceNodes(options.ToArray());
return MvcHtmlString.Create(selectDoc.ToString());
}
这允许我使用新的SelectListWithAttributes类作为属性创建下拉列表。基本上,它为下拉列表创建HTML,将其解析为XML文档,然后将HtmlAttributes数组中的任何项添加为下拉列表中每个项的附加属性。
第三,在我的ViewModel代码中,我有以下内容:
private List<SelectListItemWithAttributes> pDropDownDatas = null;
public List<SelectListItemWithAttributes> DropDownDatas {
get {
var DropDownDataItems = (
from c in db.GetDropDownDataList(1, 1000)
where c.AccountTypeID == this.AccountTypeID
select new SelectListItemWithAttributes() { Text = c.Title, Value = c.ID.ToString(), HtmlAttributes = new Dictionary<string, string> { { "data-callback", c.RequiresCallback.ToString().ToLower() } } } ).ToList()
;
DropDownDataItems.Insert(0, new SelectListItemWithAttributes() { Text = "-- Select --", Value = "", HtmlAttributes = new Dictionary<string, string> { { "data-callback", "false" } } });
return DropDownDataItems;
}
}
这将构建将最终填充下拉列表的SelectListItemsWithAttributes列表。这可能是在控制器而不是视图模型中,我只是选择使其成为我的viewmodel的属性。
最后,在视图中它看起来像这样:
@Html.DropDownListWithItemAttributesFor(m => m.DropDownDataID, Model.DropDownDatas)
这将使用viewmodel中包含SelectListItemsWithAttributes列表的属性显示页面上的下拉列表。
我从互联网上找到的各种解决方案中构建了这个解决方案,所以这对我来说不是原创的,但我把它放在一起对我有用的东西。
希望这可以帮助您解决问题。
答案 2 :(得分:8)
在应该接收表单提交的控制器操作内部,您可以使用所选值的id来查询数据库,以便获取长显示名称并执行您打算用它做的任何操作。
DropDownListFor
帮助程序不支持向选项添加HTML5 data-*
属性,但即使这样做,它们也不会作为标准表单提交的一部分发送。您将不得不使用javascript使用其他技术(隐藏字段,AJAX,查询字符串参数......)将它们发送到服务器。
但是如果由于某种原因你需要在选项标签上有其他属性,你总是可以写一个自定义助手。
答案 3 :(得分:2)
@nikeaa感谢您的代码。我发现它有一些问题(例如,当选项列表为空时,选择没有正确呈现;您不需要替换选项,只需修改它们,否则选择的某些属性将被删除)并且我添加了一些额外的参数,以充分利用DropDownListFor的强大功能。这是我的方法版本:
public static MvcHtmlString DropDownListWithItemAttributesFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<SelectListItemWithAttributes> selectList,
string optionLabel, IDictionary<string, object> htmlAttributes)
{
if (selectList == null || !selectList.Any())
return htmlHelper.DropDownListFor(expression, selectList, optionLabel, htmlAttributes);
var selectDoc = XDocument.Parse(htmlHelper.DropDownListFor(expression, selectList, optionLabel, htmlAttributes).ToString());
var options = selectDoc.Element("select").Descendants().ToArray();
for (int i = 0; i < options.Length; i++)
{
var option = options[i];
var attributes = selectList.ElementAt(i);
foreach (var attribute in attributes.Attributes)
option.SetAttributeValue(attribute.Key, attribute.Value);
}
return MvcHtmlString.Create(selectDoc.ToString());
}
答案 4 :(得分:1)
现在回到这里。虽然@nikeaa的答案肯定是一个可行的解决方案,我认为它有点重量级,特别是使用XDocument。作为提醒我正在处理的是TypeType(汽车)和SubType(汽车类型列表 - Viper,Granada,Hunter,Zodiac,Wolsley 1660等)。 TypeType也可以是卡车,自行车等。 所以这就是我解决它的方法:
我在Controller上添加了一个JsonResult方法,以返回一个具有我想要的3个属性的匿名对象:
public class VehicleController : Controller
{
// etc.
public JsonResult GetSubTypesForTypeType(string typeTypeName)
{
var cars = pronova2Repository.GetTypeWithSubTypes(typeTypeName);
return cars == null
? Json(new object[0], JsonRequestBehavior.AllowGet)
: Json(cars.SubTypes.OrderBy(s => s.Name).Select(
s => new { s.SubTypeID, s.Name, s.Description }).ToArray(),
JsonRequestBehavior.AllowGet);
}
// etc.
}
然后在js:
填充下拉列表:
// populate the cars drop down when the select list is available
if ($('select#SubTypeID').length) {
var carsSelect = $('select#SubTypeID');
var carsList = populateCarsList("CARS");
var carsListHtml = createCarsSelectList(carsList);
carsSelect.html('');
carsSelect.append(carsListHtml);
$('#SubTypeID').change(function (e) {
clearFormData();
});
}
通过ajax调用调用函数来获取子类型(汽车):
function populateCarsList(typeTypeName) {
var carsList;
$.ajax({
url: '/Vehicle/GetSubTypesForTypeType',
data: { typeTypeName: typeTypeName },
async: false
}).done(function (data) {
carsList = data;
}).error(function (msg, url, line) {
alert("Error retrieving cars from Vehicle/GetSubTypesForTypeType. Error message: " + line);
});
return carsList;
}
创建选择列表的功能,其中添加的描述为“data- *”属性:
function createCarsSelectList(selectData) {
var html = '',
len = selectData.length,
selected,
description;
for (var i = 0; i < len; i++) {
// "Viper" should be selected by default
if (selectData[i].Name.toLocaleUpperCase() === "VIPER") {
selected = ' selected="selected" ';
} else {
selected = '';
}
// Add the description (as a "data-" attribute), some descritions are null
if (selectData[i].Description != null) {
description = selectData[i].Description;
} else {
description = '';
}
html += '<option value="' + selectData[i].SubTypeID + '" data-description="' + description + '"' + selected + '>' + selectData[i].Name + '</option>';
}
return html;
}