[英]Adding html class tag under <option> in Html.DropDownList
我一直在尋找有關如何在我的 html.dropdownlist 上添加 HTML 類標記的答案。 這是代碼
<%: Html.DropDownList("PackageId", new SelectList(ViewData["Packages"] as IEnumerable, "PackageId", "Name", Model.PackageId))%>
我想在 select 元素下為選項添加類,以便我可以使用這個鏈式 select :
<select id="category">
<option value="1">One</option>
<option value="2">Two</option>
</select>
<select id="package">
<option value="1" class="1">One - package1</option>
<option value="2" class="1">One - package2</option>
<option value="3" class="2">Two - package1</option>
<option value="4" class="2">Two - package2</option>
</select>
$("#series").chained("#mark");
我已經為 DropDownlistFor 擴展方法完成了這項工作,而不是您使用的 DropDownList,但您可能可以自己弄清楚。 這些東西主要是從 MVC 來源復制/粘貼的。 您可以在此處找到資源。
public class ExtendedSelectListItem : SelectListItem
{
public object htmlAttributes { get; set; }
}
public static partial class HtmlHelperExtensions
{
public static MvcHtmlString ExtendedDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<ExtendedSelectListItem> selectList, string optionLabel, object htmlAttributes)
{
return SelectInternal(htmlHelper, optionLabel, ExpressionHelper.GetExpressionText(expression), selectList, false /* allowMultiple */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, string optionLabel, string name, IEnumerable<ExtendedSelectListItem> selectList, bool allowMultiple, IDictionary<string, object> htmlAttributes)
{
string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
if (String.IsNullOrEmpty(fullName))
throw new ArgumentException("No name");
if (selectList == null)
throw new ArgumentException("No selectlist");
object defaultValue = (allowMultiple) ? GetModelStateValue(htmlHelper, fullName, typeof(string[])) : GetModelStateValue(htmlHelper, fullName, typeof(string));
// If we haven't already used ViewData to get the entire list of items then we need to
// use the ViewData-supplied value before using the parameter-supplied value.
if (defaultValue == null)
defaultValue = htmlHelper.ViewData.Eval(fullName);
if (defaultValue != null)
{
IEnumerable defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue };
IEnumerable<string> values = from object value in defaultValues select Convert.ToString(value, CultureInfo.CurrentCulture);
HashSet<string> selectedValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase);
List<ExtendedSelectListItem> newSelectList = new List<ExtendedSelectListItem>();
foreach (ExtendedSelectListItem item in selectList)
{
item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text);
newSelectList.Add(item);
}
selectList = newSelectList;
}
// Convert each ListItem to an <option> tag
StringBuilder listItemBuilder = new StringBuilder();
// Make optionLabel the first item that gets rendered.
if (optionLabel != null)
listItemBuilder.Append(ListItemToOption(new ExtendedSelectListItem() { Text = optionLabel, Value = String.Empty, Selected = false }));
foreach (ExtendedSelectListItem item in selectList)
{
listItemBuilder.Append(ListItemToOption(item));
}
TagBuilder tagBuilder = new TagBuilder("select")
{
InnerHtml = listItemBuilder.ToString()
};
tagBuilder.MergeAttributes(htmlAttributes);
tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */);
tagBuilder.GenerateId(fullName);
if (allowMultiple)
tagBuilder.MergeAttribute("multiple", "multiple");
// If there are any errors for a named field, we add the css attribute.
ModelState modelState;
if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState))
{
if (modelState.Errors.Count > 0)
{
tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}
}
tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name));
return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
}
internal static string ListItemToOption(ExtendedSelectListItem item)
{
TagBuilder builder = new TagBuilder("option")
{
InnerHtml = HttpUtility.HtmlEncode(item.Text)
};
if (item.Value != null)
{
builder.Attributes["value"] = item.Value;
}
if (item.Selected)
{
builder.Attributes["selected"] = "selected";
}
builder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(item.htmlAttributes));
return builder.ToString(TagRenderMode.Normal);
}
}
這是@john-landheer 解決方案的改進版本。
情況有所改善:
GetModelStateValue()
問題GetModelStateValue()
修復DropDownList()
擴展方法不顯眼的驗證屬性將按照應有的方式呈現
using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Web; using System.Web.Mvc; namespace App.Infrastructure.Helpers { public class ExtendedSelectListItem : SelectListItem { public object HtmlAttributes { get; set; } } public static class ExtendedSelectExtensions { internal static object GetModelStateValue(this HtmlHelper htmlHelper, string key, Type destinationType) { System.Web.Mvc.ModelState modelState; if (htmlHelper.ViewData.ModelState.TryGetValue(key, out modelState)) { if (modelState.Value != null) { return modelState.Value.ConvertTo(destinationType, null /* culture */); } } return null; } public static MvcHtmlString ExtendedDropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<ExtendedSelectListItem> selectList) { return ExtendedDropDownList(htmlHelper, name, selectList, (string)null, (IDictionary<string, object>)null); } public static MvcHtmlString ExtendedDropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<ExtendedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes) { return ExtendedDropDownListHelper(htmlHelper, null, name, selectList, optionLabel, htmlAttributes); } public static MvcHtmlString ExtendedDropDownListHelper(this HtmlHelper htmlHelper, ModelMetadata metadata, string expression, IEnumerable<ExtendedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes) { return SelectInternal(htmlHelper, metadata, optionLabel, expression, selectList, false, htmlAttributes); } public static MvcHtmlString ExtendedDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IEnumerable<ExtendedSelectListItem> selectList, string optionLabel, object htmlAttributes) { if (expression == null) throw new ArgumentNullException("expression"); ModelMetadata metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData); return SelectInternal(htmlHelper, metadata, optionLabel, ExpressionHelper.GetExpressionText(expression), selectList, false /* allowMultiple */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); } private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata, string optionLabel, string name, IEnumerable<ExtendedSelectListItem> selectList, bool allowMultiple, IDictionary<string, object> htmlAttributes) { string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name); if (String.IsNullOrEmpty(fullName)) throw new ArgumentException("No name"); if (selectList == null) throw new ArgumentException("No selectlist"); object defaultValue = (allowMultiple) ? htmlHelper.GetModelStateValue(fullName, typeof(string[])) : htmlHelper.GetModelStateValue(fullName, typeof(string)); // If we haven't already used ViewData to get the entire list of items then we need to // use the ViewData-supplied value before using the parameter-supplied value. if (defaultValue == null) defaultValue = htmlHelper.ViewData.Eval(fullName); if (defaultValue != null) { IEnumerable defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue }; IEnumerable<string> values = from object value in defaultValues select Convert.ToString(value, CultureInfo.CurrentCulture); HashSet<string> selectedValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase); List<ExtendedSelectListItem> newSelectList = new List<ExtendedSelectListItem>(); foreach (ExtendedSelectListItem item in selectList) { item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text); newSelectList.Add(item); } selectList = newSelectList; } // Convert each ListItem to an <option> tag StringBuilder listItemBuilder = new StringBuilder(); // Make optionLabel the first item that gets rendered. if (optionLabel != null) listItemBuilder.Append( ListItemToOption(new ExtendedSelectListItem() { Text = optionLabel, Value = String.Empty, Selected = false })); foreach (ExtendedSelectListItem item in selectList) { listItemBuilder.Append(ListItemToOption(item)); } TagBuilder tagBuilder = new TagBuilder("select") { InnerHtml = listItemBuilder.ToString() }; tagBuilder.MergeAttributes(htmlAttributes); tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */); tagBuilder.GenerateId(fullName); if (allowMultiple) tagBuilder.MergeAttribute("multiple", "multiple"); // If there are any errors for a named field, we add the css attribute. System.Web.Mvc.ModelState modelState; if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState)) { if (modelState.Errors.Count > 0) { tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName); } } tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(fullName, metadata)); return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal)); } internal static string ListItemToOption(ExtendedSelectListItem item) { TagBuilder builder = new TagBuilder("option") { InnerHtml = HttpUtility.HtmlEncode(item.Text) }; if (item.Value != null) { builder.Attributes["value"] = item.Value; } if (item.Selected) { builder.Attributes["selected"] = "selected"; } builder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(item.HtmlAttributes)); return builder.ToString(TagRenderMode.Normal); } } }
這對於內置於 ASP.NET MVC 的 DropDownList 幫助程序是不可能的。 因此,如果您需要這樣做,您將不得不編寫自己的助手。 您可以查看使用 TagBuilder 生成選項的 ASP.NET MVC 的源代碼,您可以在自定義實現中附加任何屬性。 另一個不太優雅的解決方案是手動遍歷視圖中的數據集並生成單個選項元素。
我首先想到的是這里的 JQuery。 您可以使用以下代碼輕松完成此操作:
$("#bla").find("option").addClass("poo");
一個簡單的解決方案:當你添加
@Html.DropDownList("someID", new SelectList(Model.selectItems),"--Select--",new { @class= "select-ddl" })
在你的 css 中再添加一個類
.select-ddl option {}
此類將應用於 HTML 中的所有選項標簽。
我寫了一個簡單地修改 html 的包裝器:
public static MvcHtmlString DisableFirstItem(MvcHtmlString htmlString)
{
return new MvcHtmlString(
htmlString.ToString()
.Replace("<option value=\"Unknown\">",
"<option disabled value=\"Unknown\">")
);
}
然后我用這個輔助函數包裝了我的 DropDownListFor :
@Html.Raw(MyHtmlHelpers.DisableFirstItem(
Html.DropDownListFor(m => m.Instrument,
new SelectList(ReflectionHelpers.GenerateEnumDictionary<OrderInstrument>(true), "Key", "Value", Model.Instrument),
new { @class = "form-control" })
))
如果需要,您顯然可以使輔助函數更復雜。
我修改了@Alexander Puchkov 的答案,以便自動創建一個 ExtendedSelectList,其中包含一個 ExtendedSelectListItems 的集合,該集合是根據傳遞給它的 Items 的屬性自動生成的,而無需手動指定每個 SelectListItem 的屬性。 它將屬性創建為“data-*”。 您可以使用函數 parms 或通過將它們列在 excludeProperties 中來排除某些屬性。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Web.UI;
namespace App.Infrastructure.Helpers.Extensions
{
public class ExtendedSelectList : SelectList
{
static readonly string[] excludedProperties = new string[] { "DateInsert", "DateUpdate" }; // Write here properties you want to exclude for every ExtendedSelectList
public ICollection<ExtendedSelectListItem> ExtendedSelectListItems { get; set; }
public ExtendedSelectList(IEnumerable items, string dataValueField, string dataTextField, object selectedValue, params string[] exclude) : base(items, dataValueField, dataTextField, selectedValue)
{
ExtendedSelectListItems = new List<ExtendedSelectListItem>();
exclude = exclude.Concat(new string[] { dataValueField, dataTextField }).ToArray();
exclude = exclude.Concat(excludedProperties).ToArray();
foreach (var selectListItem in this.AsEnumerable())
{
var extendedItem = new ExtendedSelectListItem() { Value = selectListItem.Value, Text = selectListItem.Text, Selected = selectListItem.Selected, Disabled = selectListItem.Disabled, Group = selectListItem.Group };
var htmlAttributes = new Dictionary<string, object>();
var item = items.Cast<object>().FirstOrDefault(x =>
{
string valueItem = DataBinder.Eval(x, DataValueField).ToString();
string valueSelectListItem = DataBinder.Eval(selectListItem, "Value").ToString();
return valueItem == valueSelectListItem;
});
foreach (PropertyInfo property in item.GetType().GetProperties())
{
if (!property.CanRead || (property.GetIndexParameters().Length > 0) || (exclude != null && exclude.Contains(property.Name)))
continue;
htmlAttributes.Add("data-" + property.Name.ToLower(), property.GetValue(item));
}
extendedItem.HtmlAttributesDict = htmlAttributes;
ExtendedSelectListItems.Add(extendedItem);
}
}
}
public class ExtendedSelectListItem : SelectListItem
{
public object HtmlAttributes { get; set; }
public Dictionary<string, object> HtmlAttributesDict { get; set; }
}
public static class ExtendedSelectExtensions
{
internal static object GetModelStateValue(this HtmlHelper htmlHelper, string key, Type destinationType)
{
System.Web.Mvc.ModelState modelState;
if (htmlHelper.ViewData.ModelState.TryGetValue(key, out modelState))
{
if (modelState.Value != null)
{
return modelState.Value.ConvertTo(destinationType, null /* culture */);
}
}
return null;
}
public static MvcHtmlString ExtendedDropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<ExtendedSelectListItem> selectList)
{
return ExtendedDropDownList(htmlHelper, name, selectList, (string)null, (IDictionary<string, object>)null);
}
public static MvcHtmlString ExtendedDropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<ExtendedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes)
{
return ExtendedDropDownListHelper(htmlHelper, null, name, selectList, optionLabel, htmlAttributes);
}
public static MvcHtmlString ExtendedDropDownListHelper(this HtmlHelper htmlHelper, ModelMetadata metadata, string expression, IEnumerable<ExtendedSelectListItem> selectList, string optionLabel, IDictionary<string, object> htmlAttributes)
{
return SelectInternal(htmlHelper, metadata, optionLabel, expression, selectList, false, htmlAttributes);
}
public static MvcHtmlString ExtendedDropDownListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression, IEnumerable<ExtendedSelectListItem> selectList,
string optionLabel, object htmlAttributes)
{
if (expression == null)
throw new ArgumentNullException("expression");
ModelMetadata metadata = ModelMetadata.FromLambdaExpression<TModel, TProperty>(expression, htmlHelper.ViewData);
return SelectInternal(htmlHelper, metadata, optionLabel, ExpressionHelper.GetExpressionText(expression), selectList,
false /* allowMultiple */, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
private static MvcHtmlString SelectInternal(this HtmlHelper htmlHelper, ModelMetadata metadata, string optionLabel, string name,
IEnumerable<ExtendedSelectListItem> selectList, bool allowMultiple,
IDictionary<string, object> htmlAttributes)
{
string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
if (String.IsNullOrEmpty(fullName))
throw new ArgumentException("No name");
if (selectList == null)
throw new ArgumentException("No selectlist");
object defaultValue = (allowMultiple)
? htmlHelper.GetModelStateValue(fullName, typeof(string[]))
: htmlHelper.GetModelStateValue(fullName, typeof(string));
// If we haven't already used ViewData to get the entire list of items then we need to
// use the ViewData-supplied value before using the parameter-supplied value.
if (defaultValue == null)
defaultValue = htmlHelper.ViewData.Eval(fullName);
if (defaultValue != null)
{
IEnumerable defaultValues = (allowMultiple) ? defaultValue as IEnumerable : new[] { defaultValue };
IEnumerable<string> values = from object value in defaultValues
select Convert.ToString(value, CultureInfo.CurrentCulture);
HashSet<string> selectedValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase);
List<ExtendedSelectListItem> newSelectList = new List<ExtendedSelectListItem>();
foreach (ExtendedSelectListItem item in selectList)
{
item.Selected = (item.Value != null)
? selectedValues.Contains(item.Value)
: selectedValues.Contains(item.Text);
newSelectList.Add(item);
}
selectList = newSelectList;
}
// Convert each ListItem to an <option> tag
StringBuilder listItemBuilder = new StringBuilder();
// Make optionLabel the first item that gets rendered.
if (optionLabel != null)
listItemBuilder.Append(
ListItemToOption(new ExtendedSelectListItem()
{
Text = optionLabel,
Value = String.Empty,
Selected = false
}));
foreach (ExtendedSelectListItem item in selectList)
{
listItemBuilder.Append(ListItemToOption(item));
}
TagBuilder tagBuilder = new TagBuilder("select")
{
InnerHtml = listItemBuilder.ToString()
};
tagBuilder.MergeAttributes(htmlAttributes);
tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */);
tagBuilder.GenerateId(fullName);
if (allowMultiple)
tagBuilder.MergeAttribute("multiple", "multiple");
// If there are any errors for a named field, we add the css attribute.
System.Web.Mvc.ModelState modelState;
if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState))
{
if (modelState.Errors.Count > 0)
{
tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName);
}
}
tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(fullName, metadata));
return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
}
internal static string ListItemToOption(ExtendedSelectListItem item)
{
TagBuilder builder = new TagBuilder("option")
{
InnerHtml = HttpUtility.HtmlEncode(item.Text)
};
if (item.Value != null)
{
builder.Attributes["value"] = item.Value;
}
if (item.Selected)
{
builder.Attributes["selected"] = "selected";
}
var attributes = HtmlHelper.AnonymousObjectToHtmlAttributes(item.HtmlAttributes);
builder.MergeAttributes(attributes);
if (item.HtmlAttributesDict != null)
{
foreach (var attribute in item.HtmlAttributesDict)
{
var key = attribute.Key.ToLower(); // We call ToLower to keep the same naming convention used by MVC's HtmlHelper.AnonymousObjectToHtmlAttributes
var value = attribute.Value?.ToString() ?? "";
builder.Attributes[key] = value;
}
}
return builder.ToString(TagRenderMode.Normal);
}
}
}
要在 Razor 中使用它,您可以:
@{
var availableLocations = new ExtendedSelectList(Model.AvailableLocations, "Id", "Value", Model.LocationId);
}
@Html.ExtendedDropDownListFor(m => Model.LocationId, availableLocations.ExtendedSelectListItems, null, new { id = "ddLocation" })
請注意“availableLocations.ExtendedSelectListItems”,因為您不能直接使用 Enumerable 項,因為它們是簡單的 SelectListItem
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.