jQuery plugin: chained select lists

A few days ago I was looking for a jQuery plugin that would allow me link select lists together, so that selecting an option in one list (the parent) would update the options in the other list (the target). I’d used linkedSelect on a previous project, but for some reason, my ISP kept returning “IP has been banned” each time I tried to browse to the site.

As it turns out, this was a good thing. Eventually, I found this post on Remy Sharp’s blog, and his selectChain plugin was almost exactly what I was looking for. Almost.
There were a few changes I needed to make first:

  1. Add support for the metadata plugin: since I’ll mostly be using this in my Django projects, being able to specify plugin options declaratively means I can wrap the plugin in a custom widget.
  2. Add support for caching
  3. Update target list when the page is loaded, if the parent list has an option selected.
  4. Preserve the selected option in the target list, if possible (as long as the updated options contain the previous option), when it is updated
  5. Add a few niceties, such as a preloader GIF :)

To use the plugin, download it and include a reference to it in your HTML page (don’t forget to include a reference to jQuery first!). I’ll assume, you’ve already written the server-side code in your choice framework. If you’d like to be able to customize the plugin behavior declaratively, for specific selects, you’ll also need to download the metadata plugin.


We’ll use the following HTML:

<form method="post" action="...">
  <label for="id_author">Author:</label>
  <select name="author" id="id_author">
    <option value="1">Enid Blyton</option>
    <option value="2">J. K. Rowling</option>
    <option value="3">Roald Dahl</option>
  <label for="id_book">Book:</label>
  <select name="book" id="id_book">

Include the following script before the closing BODY tag, or in your HEAD:

$(function() {
    parent: '#id_author',
    url: 'http://your.server/app',
    value: 'id',
    label: 'text'

That’s it. Your server application should return a JSON-encoded list of objects, having “id” and “text” properties. The “id” will be used as the value of the generated option, the “text” as its label. Selecting an author from the list, should display a list of their books.

If you’re using the metadata plugin, you can move the options into the target select list. Change the HTML for the “book” list to this:

<select name="book" id="id_book" class="chainedSelect {parent: '#id_author', url: 'http://your.server/app', value: 'id', label: 'text'}">

Then, replace the previous script with the following:

$(function() {

Simpler, isn’t it?


Here’s a list of options you can pass, either as metadata, or in the call to “$.chainedSelect”, to customize the plugin:

  • parent: A jQuery ID selector, for the parent list – must begin with a ‘#’. Required.
  • url: The URL to the server component. The server will be passed a single querystring parameter named “q”, whose value will be the selected option in the parent list. It should return a JSON-encoded list of objects, which will be used to populate the target list. Required.
  • value: The property in the objects returned from the server, which should be used as the value for the generated option. Defaults to “pk”
  • label: The property in the objects returned from the server, which should be used as the label for the generated option. Defaults to “name”
  • type: The HTTP method used to submit the data to the server – defaults to “GET”.
  • preloadUrl: A URL to a GIF image, displayed while waiting for an AJAX request to complete. For best results, images should be as small as possible – no larger than 16×16 pixels
  • error: Use this to specify a function that will be called if the AJAX request returns an error


jQuery, of course (tested with 1.2.6)
A server-side component, to generate the JSON used to populate the select lists


jquery.chainedSelect source (6.3KB)
jquery.chainedSelect minified (2.1KB)

If you find this useful, or have any questions, ideas or issues, leave a comment.


8 thoughts on “jQuery plugin: chained select lists

  1. Hi,

    I am trying to use your script but can’t figure out what data it is expecting from the server. For example it expects a length property that you didn’t mention :P

    Can you give me a sample of the json returned. I am trying to implement this with Django.

  2. @Bruce: The script expects a list of objects with properties “pk” and “name” (these can be overwritten using the “value” and “label” options)…that’s all. No hidden “length” properties of any kind, I swear :)

    Here’s a sample of the JSON being returned in one of the projects I’m using this in:

        {"pk": 380, "name": "Ado"}, 
        {"pk": 381, "name": "Agatu"}, 
        {"pk": 382, "name": "Apa"}, 
        {"pk": 383, "name": "Buruku"}, 
        {"pk": 384, "name": "Gboko"}, 
        {"pk": 385, "name": "Guma"}, 
        {"pk": 386, "name": "Gwer-East"}, 
        {"pk": 387, "name": "Gwer-West"}, 
        {"pk": 388, "name": "Katsina-Ala"}, 
        {"pk": 389, "name": "Konshisha"}, 
        {"pk": 390, "name": "Kwande"}, 
        {"pk": 392, "name": "Makurdi"}, 
        {"pk": 393, "name": "Obi"}, 
        {"pk": 394, "name": "Ogbadibo"},
        {"pk": 399, "name": "Tarka"},
        {"pk": 402, "name": "Vandeikya"}

    Here’s the view that does the filtering and returns the JSON:

    from django.http import HttpResponse, Http404
    from django.utils.encoding import smart_str
    from django.utils.simplejson import dumps
    def filter(request, model_class, field_name):
            kwargs = {smart_str(field_name): request.GET['q']}
        except KeyError:
            raise Http404
        qs = model_class.objects.filter(**kwargs).values('pk', 'name')
        response = HttpResponse(
        return response

    My urlconf looks something like this:

    urlpatterns = patterns('',
        url(r'^locations/lga/find-by-(?P<field_name>\w+)/$', 'filter', {'model_class': Lga},  name='...')
  3. Cristian

    Small tip: I’m using jquery 1.7.2 and I have to change $.attr() to $.prop() when setting/unsetting disabled state of selects lists.

  4. Kapone

    Line 112: target.attr(‘disabled’, ”).trigger(‘change’);
    should be:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s