Corey Coogan

Python, .Net, C#, ASP.NET MVC, Architecture and Design

  • Subscribe

  • Archives

  • Blog Stats

    • 112,314 hits
  • Meta

Client Side Dependent Dropdowns with JQuery without AJAX

Posted by coreycoogan on September 12, 2009

There are several terms to describe the common UI technique of having 2 dropdown lists, with the selections of the first dropdown changing the options of the second.  Common terms for this include Dependent Dropdowns, Context Sensitive Dropdowns,  Contextual Dropdowns and probably others.

I recently had a requirement for this functionality in a control in an ASP.NET MVC project.  When I searched for some samples on how to do this in JQuery, I realized that all the samples I found used AJAX to populate the second list.  In this particular case, it made more sense to keep everything on the client, so that’s what I developed.  This post is about how I accomplished this using JQuery, JSON.NET and a ViewModel with a couple extension methods.  If you’re looking for ways to do this with AJAX, you’ll have to read one of the many other examples in the blogosphere.

The Requirement

The user needs a way to choose a color for a product.  The chosen color is categorized under a parent color (Blue.Baby, Blue.Sky, Yellow.Banana, Yellow.Lemon).  The user should be able to first pick a parent color and then view a list of all child colors from which to pick.  The catalog of color selections is stored in a database and should be used to drive the dropdowns.  The dropdowns are just a helper as the user is able to input any color name they wish, regardless of whether or not it appears in the second dropdown.  Up to 5 colors can be chosen per product, so the color selection should be a control that can be repeated on a view, however, this post will ignore that requirement and show how this can be accomplished in a singular fashion.

The  Object Model

The ViewModel that drives the View where this functionality resides contains an IList<VendorColor> property, which will be used to populate the dropdowns.  The VendorColor class looks like this:


public class VendorColor
 {
      readonly int _vendorColorId;
      readonly string _primaryColor;
      readonly string _secondaryColor;

 public VendorColor(int vendorColorId, string primaryColor,
                                       string secondaryColor)
 {
      _vendorColorId = vendorColorId;
      _primaryColor = primaryColor;
      _secondaryColor = secondaryColor;
 }

 public int VendorColorId { get { return _vendorColorId; } }

 public string PrimaryColor { get { return _primaryColor; } }

 public string SecondaryColor { get { return _secondaryColor; } }
 }

Extension Methods

In order to keep everything on the client, we’ll need to get the pertinent data from the collection of VendorColor objects to the View so it’s accessible by JQuery and JavaScript.  To do this, 2 extension methods were written to serialize the required data to JavaScript objects.

First, we need to gather the distinct PrimaryColor values from the list of VendorColor objects and get them into an array.  Here’s what that extension method looks like.


public static string PrimaryColorsAsJsArray(this List colors)
 {
 //get the distinct primary colors from the collection
 var primaries =
 (from c in colors
 select c.PrimaryColor).Distinct();

 //append each value into a JavaScript Array string, start with an empty string for blank option
 StringBuilder sb = new StringBuilder("var arrPrimary = [\"\",");
 foreach (var primary in primaries)
 sb.AppendFormat("\"{0}\",", primary);

 //remove the last comma and add ending bracket
 sb.Remove(sb.Length - 1, 1);
 sb.Append("];");

 return sb.ToString();

 }

This results in the following javascript:

var arrPrimary = ["","Red","Blue","Green","Yellow"];

The next extension method will be used to serialize the entire collection of VendorColor objects to JSON objects that we can later parse with JQuery and fill our dependent dropdown list. This is ridiculously easy with the help of the awesome JSON.NET library. Check out what can be done in one line of code!


public static string VendorColorsToJsonArrary(this List colors)
 {
 return "var arrSecondary = " +
 Newtonsoft.Json.JsonConvert.SerializeObject(colors) + ";";
 }

This results in the following javascript (formatted for readability):

var arrSecondary = [
                    {"VendorColorId":1,"PrimaryColor":"Red","SecondaryColor":"blood"},
                    {"VendorColorId":2,"PrimaryColor":"Red","SecondaryColor":"apple"},
                    {"VendorColorId":3,"PrimaryColor":"Blue","SecondaryColor":"sky"},
                    {"VendorColorId":4,"PrimaryColor":"Blue","SecondaryColor":"baby"},
                    {"VendorColorId":5,"PrimaryColor":"Green","SecondaryColor":"lime"},
                    {"VendorColorId":6,"PrimaryColor":"Green","SecondaryColor":"lettuce"},
                    {"VendorColorId":7,"PrimaryColor":"Yellow","SecondaryColor":"sunshine"},
                    {"VendorColorId":8,"PrimaryColor":"Yellow","SecondaryColor":"lemon"}
                 ];

The View

Now let’s tie it all together by seeing the view and all the javascript that makes this work. It should be noted that my view is utilizing the latest version of the JQuery library.


    //use vars for my controls so JQuery and Javascript won't have to retype each time
    var primaryDd = '#PrimaryColor';
    var secondaryDd = '#SecondaryColor';

 

Now the script that makes all this work, complete with comments. In the real world, this is stored in an external .js file, as it should be. This keeps the views cleaner and Google favors it for SEO. Keep in mind that the script is using the vars defined above.

function ClearDd1(dropDown1) {
    $(dropDown1)[0].options.length = 0;
}

function ClearDd2(dropDown2) {
    $(dropDown2)[0].options.length = 0;
}

function BindSecondary(dd1, dd2) {

    //clear the options before rebinding them
    ClearDd2(dd2);

    //get the selected value from dropdown 1
    var sel = $(dd1).val();

    //use the JQuery grep function to find all objects in my JSON collection
    //where the PrimaryColor equals the selection from the first dropdown.
    //this is really the key to making this work elegantly
    var arr = $.grep(arrSecondary, function(a) { return a.PrimaryColor == sel; });

    //for each JSON object, write an option to the second dropdown
    $(arr).each(
                function(i) {
                    $("").attr("value", arr[i].VendorColorId)
                                      .text(arr[i].SecondaryColor).appendTo(dd2);
                });
}

function SelectColor(dd2, hid, txt) {

    //the selected value from the second dropdown
    var selVal = $(dd2).val();

    //make sure a color has been selected
    if (selVal == '') {
        alert('You must select a secondary color or cancel');
        return false;
    }

    //grab the text from the selected option
    var selText = $(dd2 + ' :selected').text();

    //store the ID, or option value, in a hidden form field
    $(hid).val(selVal);
    
    //send the selected color into a text field
    $(txt).val(selText);
}

Conclusion

JQuery and ASP.NET Ajax has made it very easy to use AJAX to accomplish dependent dropdowns. In many cases, it’s wasteful and unnecessary to go to the server for this information over and over again. In such cases it can be advantageous to do this purely on the client. Using JSON.NET to serialize objects from .NET to JSON and using JQuery and its “grep()”, “each()” and “val()” methods to get the right data and handle population and selection. This solution didn’t take too long to develop, but if you know a better way, I’d love to hear about it.

One Response to “Client Side Dependent Dropdowns with JQuery without AJAX”

  1. thatflash said

    Thanks! I will recommend this to all my friends.

Sorry, the comment form is closed at this time.