2011-09-24 83 views
34

我一直在尋找如何在我的html.dropdownlist上添加HTML類標記的答案。這裏是代碼在Html.DropDownList中添加<option>下的html類標記

<%: Html.DropDownList("PackageId", new SelectList(ViewData["Packages"] as IEnumerable, "PackageId", "Name", Model.PackageId))%> 

我要添加類的選項中選擇元素,這樣我可以用這個鏈接的選擇:

是我腦海
<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"); 
+1

什麼錯誤? –

回答

2

的第一件事是JQuery的在這裏。您可以輕鬆地下面的代碼做到這一點:

$("#bla").find("option").addClass("poo"); 
+2

我不能那樣做。我需要這個班級來改變我的鏈接選擇的值。 – paul

+0

@paul好的,但這並不意味着它不會工作。將上面的代碼放在必要的JQuery代碼之前,然後在您需要它們之前設置這些類。 – tugberk

+1

+1加入poo大聲笑 – 2014-01-14 11:19:17

5

這是不可能的內置於ASP.NET MVC DropDownList的幫手。因此,如果您需要這樣做,您將不得不編寫自己的幫手。您可以看看使用TagBuilder生成選項的ASP.NET MVC的源代碼,並且您可以在自定義實現中追加任何屬性。另一個較不優雅的解決方案是手動循環查看視圖中的數據集並生成單個選項元素。

+1

任何想法,如果這已被更新版本的框架(5.2.3)涵蓋?這是跛腳,你必須編寫自定義代碼,以實現相當常見的使用行爲:( –

47

我已經爲DropDownlistFor擴展方法做了這個,而不是你使用的DropDownList,但你可以自己弄清楚。這些東西大部分是從MVC源文件複製/粘貼的。你可以找到來源here

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

這真的很好,除了缺少GetModelStateValue()方法是(現在?)內部。這是涵蓋了這個問題:http: //stackoverflow.com/questions/6967148/not-able-to-access-getmodelstatevalue-in-custom-control-in-asp-net-mvc2 – Dann

+2

這是更正的行:'object defaultValue =(allowMultiple)?htmlHelper.GetModelStateValue (fullName,typeof(string [])):htmlHelper.GetModelStateValue(fullName,typeof(string));' –

+0

我最終採取了相同的方法,以便我可以獲得html選擇集的「title」屬性。你顯示更多關於懸停的信息(已授予,可能對移動設備沒有用處) –

0

我寫了一個包裝,只需修改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" }) 

     )) 

你可以明顯地使輔助功能更如果你想要複雜的話。

9

這是@ john-landheer解決方案的一個小改進版本。

事情好轉:

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

太棒了!我試着翻譯成vb.net,並且有一個警告:'Variable'modelState'在被賦值之前通過引用傳遞。運行時會導致空引用異常。「這是否有任何影響? – roland