2011-09-24 9 views
34

Ho cercato risposte su come aggiungere un tag di classe HTML sul mio html.dropdownlist. Ecco il codiceAggiunta del tag di classe html sotto <option> in Html.DropDownList

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

voglio aggiungere le classi per le opzioni sotto l'elemento di selezione in modo che posso usare questo incatenato selezionare:

<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

Qual è il errore? –

risposta

2

La prima cosa che mi viene in mente è JQuery qui. Si può fare questo con il seguente codice facilmente:

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

non posso farlo. ho bisogno che la classe cambi i valori per la mia selezione concatenata. – paul

+0

@paul Ok, ma questo non significa che non funzionerà. metti il ​​codice sopra prima del tuo codice JQuery necessario, quindi le classi verranno impostate prima che tu ne abbia bisogno. – tugberk

+1

+1 per aggiungere po '... lol –

5

Questo non è possibile con l'aiuto DropDownList che è costruito in ASP.NET MVC. Di conseguenza dovrai scrivere il tuo aiutante personale se hai bisogno di farlo. Puoi dare un'occhiata al codice sorgente di ASP.NET MVC che utilizza TagBuilder per generare le opzioni e puoi aggiungere qualsiasi attributo nella tua implementazione personalizzata. Un'altra soluzione meno elegante consiste nel passare manualmente il set di dati nella vista e generare singoli elementi di opzione.

+1

Qualche idea se questo è stato trattato nella versione più recente del framework (5.2.3)? È schifo che devi scrivere codice personalizzato per ottenere un comportamento d'uso abbastanza comune :( –

47

Ho eseguito questa operazione per il metodo di estensione DropDownlistFor, non per DropDownList, ma probabilmente lo si può capire da soli. Questa roba è principalmente copia/incolla dai sorgenti MVC. Puoi trovare le fonti 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

Questo è stato veramente buono, a parte il metodo GetModelStateValue() che è (ora?) Interno. Questo è coperto da questa domanda: http: //stackoverflow.com/questions/6967148/not-able-to-access-getmodelstatevalue-in-custom-control-in-asp-net-mvc2 – Dann

+2

Ecco la riga corretta: 'object defaultValue = (allowMultiple)? htmlHelper.GetModelStateValue (fullName, typeof (string [])): htmlHelper.GetModelStateValue (fullName, typeof (stringa)); ' –

+0

Ho finito per assumere lo stesso approccio in modo da ottenere l'attributo" title "di un set di selezione html. per mostrare più informazioni al passaggio del mouse (garantito, probabilmente non utile nel cellulare) –

0

ho scritto un wrapper che modifica semplicemente il codice HTML:

public static MvcHtmlString DisableFirstItem(MvcHtmlString htmlString) 
    { 
     return new MvcHtmlString(
      htmlString.ToString() 
      .Replace("<option value=\"Unknown\">", 
        "<option disabled value=\"Unknown\">") 
     ); 
    } 

e poi ho avvolto la mia DropDownListFor con questa funzione di supporto:

 @Html.Raw(MyHtmlHelpers.DisableFirstItem(

      Html.DropDownListFor(m => m.Instrument, 
      new SelectList(ReflectionHelpers.GenerateEnumDictionary<OrderInstrument>(true), "Key", "Value", Model.Instrument), 
      new { @class = "form-control" }) 

     )) 

Si potrebbe, ovviamente, rendere la funzione di supporto più sofisticato se vuoi.

9

Ecco una versione leggermente migliorata della soluzione di @ john-landheer.

Le cose migliorano:

  • problema con GetModelStateValue() fisso metodo di estensione
  • DropDownList() aggiunto
  • convalida discreto attributi sarà reso proprio come dovrebbero

    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

Grande! Ho provato a tradurre in vb.net e c'è un avvertimento: 'Variable 'modelState' viene passato per riferimento prima che sia stato assegnato un valore. Potrebbe verificarsi un'eccezione di riferimento null al runtime. Ciò ha qualche effetto? – roland

Problemi correlati