You are free to browse all of the content on this site, however if you want to post comments or replies you will need to register for a free account. Becoming a registered member also disables some of the more annoying ads whilst you are logged in.

jQuery: Dependant Selects Tutorial

In the preivious article, we learned how to create a plug-in. In this article we're going to use that pattern to create a dependent selects plug-in.

A dependent select is when a form select box's options depend on the values of a previous form select box. Two examples of this would be a USA State selector, which then filled the next box with cities from that state. Another example would be a car make selector (ie. Ford) which then displayed models (ie. Taurus, Bronco, F-150).
Why would you want to do this? Primarily for useability. In the case of car make/model, there are about 130 makes, but there are over 2000 models. If you didn't use javascript, you'd have a model select that was 2279 items long! That's pretty unwieldy.

Remember the source code for this project is attached at the end! (Both a sample HTML document, and the javascript)

01: Pick A Data Source

In making a plug-in like this, your first decision has to be about how it's going to work. Where is the data for the 2nd select going to come from? There are two options:

In many cases you want your web pages to work without javascript, relying on script to only enhance the user experience. If we use AJAX to load the data, then users without javascript won't see any data in the second or subsequent selects. All 2000+ options is better then no options.

02: Design the API

API means "application programming interface" -- or in more simple terms, we mean "how will the plug-in be used?". The first thing I'm going to do is create a call to the mythical plug-in.

This syntax makes sense; it allows us to specify a dependent select, and additional selects that would fire in a chain if there's more then one. For example, Country >> State >> City would look like this:

Code:

#('#country').dependent({
chain : ['#state', '#city']
});

03: Other Assumptions

We're going to assume that slaved selects are already pre-populated with data because we want the page to work without javascript.

We're also going to assume the code for the selects has been set up properly, so our script can know what information is related to what options. To make that happen, we're going to use optgroups. Optgroups are part of HTML that allows you to put a non-selectable label above a group of options in a select. The label of each optgroup will identify which options belong with the choice from the previous select. Here's an example to help make it more clear:

Now, imagine that with thirty countries, each with many states/provinces - the number of cities could easily be in the thousands. There could also be duplicate cities - Albany, NY, USA and Albany, Western Australia. This HTML is the format our plug-in will expect the selects to be in.

04: Processing the Selects

When the plug-in is called on a select there's not going to be much to do outside of the main this.each loop (see the previous article for the general plug-in architecture). However once we get into the loop, we have to parse the select options and stuff them into an array for later use. The array we're going to put everything in will be stored as opts.data.

The first thing we're going to process is the selects listed in the chain option. Here's the beginning of our main loop:

Code:

this.each(function() {
$.each(opts.chain, function(index, selectID) {

In our example, this means we'll be looping over both the #state and #city selects. The data for each select will be stored as an array indexed by the optgroup label for those selects. Imagine it something like this:

Code:

array['TX'] = "<option>Dallas</option><option>Houston</option>";

Each option is not stored separately -- it doesn't have to be. They are stored as option groups since they will be loaded as option groups. Our next few lines of code will help readability, and create the array:

Code:

// substr is used to strip off the # at the start of the string
var ident = selectID.substr(1);
var selectHTML = $(selectID).html();
opts.data[indent] = {};

Now we need another loop to move through the select's option groups. Because the variable selectHTML only stores the inside of the select, we're going to wrap it in a select tag when we work with it, for traversal reasons.

The previous line will iterate through each optgroup contained in the select we're working on. The next step is to fetch the HTML for the complete optgroup -- including the optgroup tag -- and the optgroup's label. We'll need the label for our array key.

That first line may seem a bit confusing. Remember there's no "outerHTML" function so we get a little tricky by cloning the tag we wish to extract, put it inside a newly created div, and then extract that div's HTML. This gets us the entire optgroup HTML.

Next we need to create some event bindings. If we are linking more then two selects, then the chain will be at least two values. In fact, we need to keep binding selects until the select we're working on doesn't have one following it. Here’s how we'll check for that:

Code:

if(opts.chain[index+1]) {

Within that if statement, we'll bind the select, because we've determined there's a select further down the chain.

If you think back to how we stored the data in our array, it becomes pretty obvious what's going on in this code. The first line gets the name of the next select, which is the 'ident' of our data array - that's the ID we want to change.

The next line changes the contents of the 'next' select to the optgroup we want. Here's a more readable version of that array value, for clarity:

Code:

opts.data[the-next-selects-name][the-current-select-value]

This pulls up the related optgroup to the selection that was just made.

The final line triggers the change event in the select because programmatically changing the values of the select does not fire this event. This means when you make a change on any select, it filters all the selects following it in the chain. You can see this pretty clearly in the attached example files, because that code includes 4 dependent selects.

06: The Last Step

There's one last step in the main $.each loop -- and outside the loop created for the values of opts.chain. Can you guess what that is? We need to bind the original select passed into the plug-in!

Now that you've read the tutorial, have a look at the source code file attached to see the complete code in one place. Because it's packaged as a plug-in you can put the javascript in its own file and include it in any page, and then use it just like any other jQuery plug-in.

In our next jQuery article, we're going to explore turning your standard forms into AJAX submitted forms. We'll continue with the theme of putting our custom code into a reusable plug-in so we can write once and reuse.