Archives

  • Categories

  • ASP.Net MVC Option Group DropDown Control

    Option Groups for drop down lists have been an HTML feature for many years now but have never been supported in any Asp.Net control. It was a bit of a shame recently whilst working on a new Asp.Net MVC web site to find that its still not possible to do out of the box.

    optiongroup

    However the good thing about MVC is that its a really easy  to write your own custom controls in the shape of HTML helpers so I thought I’d go about writing my own.

    What did I want the control to do?

    Firstly I wanted it to be strongly typed so no magic strings. I also wanted to be able to pass the control an enumerable collection of objects and use lambda expressions to tell the control which properties to render the text, value and how to group the dropdown items by.

    
    <%= Html.OptionGroupDropDownList(
              ViewData.Model.Cars,
              car =>  car.CountryOfOrigin,
              car => car.Brand,
              car => car.Brand,
              car => car.Brand == "BMW")%>
    

    Line 2 above represents the collection of cars we wish to render as option items.
    Line 3 is the property value of a car we wish to group them by.
    Line 4 is the property value of a car we wish to use as the option value.
    Line 5 is the property value a car we wish to use for the option text.
    Line 6 is a condition we can supply to tell the control which drop down item should be selected.

    which renders HTML that looks something a little like this:

    
    

    Ok so the code looks like this..

    public static string OptionGroupDropDownList<T, TProperty, TProperty1, TProperty2>
    ( this HtmlHelper htmlHelper,
      string name,
      string optionLabel,
      IEnumerable<T> collection,
      Func<T, TProperty> optionGroupProperty,
      Func<T, TProperty1> optionValueProperty,
      Func<T, TProperty2> optionTextProperty,
      Func<T, bool> isSelectedCondition)
    {
          var groupedCollection = collection.GroupBy(optionGroupProperty);
    
          // We are trying to generate the Html that looks something like this...
          //<select>
          //  <optgroup label="Swedish Cars">
          //      <option value="volvo">Volvo</option>
          //      <option value="saab">Saab</option>
          //  </optgroup>
          //</select>";
          using (var stringWriter = new StringWriter())
          using (var writer = new HtmlTextWriter(stringWriter))
          {
              writer.AddAttribute(HtmlTextWriterAttribute.Name, name);
              writer.AddAttribute(HtmlTextWriterAttribute.Id, name);
              //<Select>
              writer.RenderBeginTag(HtmlTextWriterTag.Select); 
    
              if(string.IsNullOrEmpty(optionLabel) == false)
               {
                   writer.RenderBeginTag(HtmlTextWriterTag.Option);
                   writer.Write(optionLabel);
                   writer.RenderEndTag();
                }
    
               // Group by our optGroup parameter...in the above example that would be
               // "Swedish Cars"
               foreach (var optionGroup in groupedCollection)
               {
                    var optionGroupLabel = optionGroup.Key;
                    // label="Swedish Cars"
                    writer.AddAttribute(Label, optionGroupLabel.ToString());
                    writer.RenderBeginTag(Optgroup); //<optgroup>  
    
                     foreach (var option in optionGroup)
                     {
                       var optionValue = optionValueProperty.Invoke(option).ToString();
                       var optionText = optionTextProperty.Invoke(option).ToString();
    
                       var isOptionSelected = isSelectedCondition.Invoke(option);
    
                       if (isOptionSelected)
                         writer.AddAttribute(HtmlTextWriterAttribute.Selected, "true");
    
                       // value = "volvo"
                       writer.AddAttribute(HtmlTextWriterAttribute.Value, optionValue); 
    
                       // <option>
                       writer.RenderBeginTag(HtmlTextWriterTag.Option);
                       // Volvo
                       writer.Write(optionText);
                       // </option>
                       writer.RenderEndTag();
                      }
                      // </optiongroup>
                       writer.RenderEndTag();
                    }
                     //</Select>
                    writer.RenderEndTag();
    
                    return stringWriter.ToString();
                }
            }
    

    One Response to “ASP.Net MVC Option Group DropDown Control”


    1. Pretty nice post. I just stumbled upon your blog and wanted to say that I have really enjoyed browsing your blog posts. In any case I’ll be subscribing to your feed and I hope you write again soon!

    Leave a Reply