Check out my latest project: Full Frontal JavaScript Conference

Auto-populating Select Boxes using jQuery & AJAX

Update: due to popular demand, I've caved in, and written a plugin and demos with multiple-select boxes populating each other and driven from MySQL.

View: Auto-populate multiple select boxes

If you are familiar with using select boxes for categorisation and sub-categories, such as ebay does when selling an item, usually this can require a lot of JavaScript to maintain the select boxes, but jQuery can hugely simplify this task by adding a dash of AJAX.

The Goal

Allow the user to select a top level category from one select box and to automatically populate the sub-category.

Prerequisites

  1. Latest copy of jQuery
  2. A basic understanding of JSON (don’t let this put you off - it’s really very, very easy)
  3. A server-side script that can respond to the AJAX request (though I’ve provided a simple example)

Demo

Our demo will specifically look to build a simple form that allows us to book human resource for a project. The top level category is the resource type, and the sub-category will list the individual’s names.

See the demo in action

How it works

Once the top level category select is changed, it sends an AJAX request for the sub-categories. The result of which are converted to select options and the sub-category select’s elements are replaced.

Unobtrusive JavaScript

First things first: as with any page that is loaded with JavaScript and AJAX functionality, it should work without JavaScript.

To achieve this for our tutorial here’s what we need to ensure:

  1. When the page is loaded, the sub-category is loaded (if the top level has a selected item).
  2. There is a ‘load sub-category’ button the user can select to re-load the page. We will hide this button with a <noscript> tag in our demo.

The Code

There are 4 parts to this demo.

  1. The page’s HTML.
  2. The server-side code to produce the dynamic page (i.e. to pre-load the select boxes when the user first visits).
  3. The jQuery & JavaScript.
  4. The JSON response (which will reuse the server-side code).

HTML

<form action="/select_demo.php">
  <label for="ctlJob">Job Function:</label>
  <select name="id" id="ctlJob">
    <option value="1">Managers</option>
    <option value="2">Team Leaders</option>
    <option value="3">Developers</option>
  </select>
  <noscript>
    <input type="submit" name="action" value="Load Individuals" />
  </noscript>
  <label for="ctlPerson">Individual:</label>
  <select name="person_id" id="ctlPerson">
    <option value="1">Mark P</option>
    <option value="2">Andy Y</option>
    <option value="3">Richard B</option>
  </select>
<input type="submit" name="action" value="Book" />
</form>

Server-side

This is just a simple example, but it should be obvious that you can expand this to go off to a database and return an object in a JSON data structure:

<?php
if ($_GET['id'] == 1) {
  echo <<<HERE_DOC
[ {optionValue: 0, optionDisplay: 'Mark'}, {optionValue:1, optionDisplay: 'Andy'}, {optionValue:2, optionDisplay: 'Richard'}]
HERE_DOC;
} else if ($_GET['id'] == 2) {
  echo <<<HERE_DOC
[{optionValue:10, optionDisplay: 'Remy'}, {optionValue:11, optionDisplay: 'Arif'}, {optionValue:12, optionDisplay: 'JC'}]
HERE_DOC;
} else if ($_GET['id'] == 3) {
  echo <<<HERE_DOC
[{optionValue:20, optionDisplay: 'Aidan'}, {optionValue:21, optionDisplay:'Russell'}]
HERE_DOC;
}?>

Note that this is not accessible. To ensure accessibility, the server side will handle the pre-population of the select boxes as the page is loaded. Here is an example (excluding the headers, footers and JavaScript) of the accessible example.

JSON Response

If I pass the server side id = 2, i.e. /select.php?id=2&ajax=true, the return value is (the ajax=true is an arbitrary flag that I’m using to differentiate between a normal user request and one done via AJAX):

[ {optionValue:10, optionDisplay: 'Remy'},
{optionValue:11, optionDisplay: 'Arif'},
{optionValue:12, optionDisplay: 'JC'}]

The enclosing square brackets denotes an array and each element is separated by a comma.

Within the array are three objects. If you’re familiar with PHP or Perl, you can basically treat these as hashes. The objects have keys (in this case two keys, one called ‘optionValue’ and one called ‘optionDisplay’), and values. Note that keys don’t need to be wrapped in quotes (though in some cases you will need them sometimes).

There are two ways which we can get the data out of this structure (assuming j is the structure):

alert(j['optionDisplay'])

Or:

alert(j.optionDisplay)

jQuery & AJAX Request

Our JavaScript is going to attach itself after the page is load, and fire an event each time the job function select box is changed.

The event will send the new value of the select box and reload the contents of the person select box.

Note that I’m be a bit naughty here, in that I’m plugging HTML directly in to the DOM.

Each item in the JSON response is looped round and used to build up the new options for the select box. As the response is an array (as mentioned earlier), we can call the .length method on it.

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" charset="utf-8">
$(function(){
  $("select#ctlJob").change(function(){
    $.getJSON("/select.php",{id: $(this).val(), ajax: 'true'}, function(j){
      var options = '';
      for (var i = 0; i < j.length; i++) {
        options += '<option value="' + j[i].optionValue + '">' + j[i].optionDisplay + '</option>';
      }
      $("select#ctlPerson").html(options);
    })
  })
})
</script>

Where to take it next

So that’s the primer. Next steps: upgrade, integrate, extend and stylise. Below is an example of the category selection when submitting an item for sale on Ebay.

Ebay Category Selection

It should be a simple next step to integrate a database behind the selection methods and create more complicated selection like this Ebay example.

Let me know if you spot any glaring errors or have any comments.

161 Responses to “Auto-populating Select Boxes using jQuery & AJAX”

  1. Thank you for example!

  2. Hi Remy,

    you saved my day. What a nice example ... and after reading it ... it seemed so simple. Thanks a lot for this.

    One minor error I'd like to mention. Instead of
    options = '' j[i].optionDisplay '';
    it should be
    options = '' j[i].name '';

    Best regards
    Stefan

  3. I changed some of the variables after someone else commented that their names may be obscure.

    Thanks for pointing that one out - I've updated the tutorial so the naming is consistent now.

  4. It's interesting that after the select box is populated, Firefox 2 will select the last option, while Opera and IE seem to work correctly and select the first option. Any idea how to fix this ? I tried to use the 'select' attribute, or use selectedIndex , nothing seems to help.

  5. @Sergui - you're right, FF does select the last item. Odd. Anyway - to fix this - I would change the following line:

    options += '<option value="' + j[i].optionValue + '">' + j[i].optionDisplay + '</option>';

    To:

    options += '<option value="' + j[i].optionValue + '"'
    if (i == 0) options += ' selected="selected"';
    options += '>' + j[i].optionDisplay + '</option>';

  6. This is nice example and it is made me esay for solve category problem thank you for this example.
    thanks and regard.

  7. For the selected issue in FF, I used the equivalent of:

    $("select#ctlPerson").html(options);
    $("option:first", "select#ctlPerson").attr("selected","selected");

    Thanks for the example.

  8. In order to be not-so-naughty, you could use jQuery's $.appendTo function so you're not plugging html directly into the dom. (I guess you really are no way around it).

    for(var i = 0; i < j.length; i ) {
    $("j[i].optionDisplay").appendTo($("select#ctlPerson"));
    }

  9. Looks like some of my code got stripped:

    ...
    $(<option value='j[i].optionValue'>j[i].optionDisplay</option>).appendTo($(”select#ctlPerson”));
    ...

  10. This is great, thanks! I removed the default options for the select#ctlPerson and added the following code which sets the value of select#ctlJob and triggers the change function.


    // trigger the initial select changer
    $("select#ctlJob").attr("value","1");
    $("select#ctlJob").trigger("change");

  11. How can we do the listbox population using Mysql

    please help me

    Thanks to al

  12. you don't happen to have an example using php & mysql-

    That would be most helpful.

    Thanks for sharing your talent.

  13. Any Jquery experts out there know how to have NONE of the options in the 2nd box selected upon populating?

  14. You could prepend a blank option to the beginning of the select with the selected="selectec" attribute.

    That would at least have an empty option be the selected choice.

  15. That example of "/select.php?id=2&ajax=true" still says id and name, instead of optionDisplay etc. Since I directly used the DB for this I used that link as example, and it took me some time to figure out why alert(j.optionDisplay) kept returning "Undefined".

    Anyway, the final appendTo part doesn't work for me. I can't even get it to add it to body for testing. Also tried a test link function with $(bleh).appendTo($('.ctlJob')); but no options are being added. And no errors in firebug either. :/

  16. @Mav - good catch - I'll update the post to fix that discrepancy.

    I've tweaked the demo a little to get around the 'last selected' problem.

    Add the following line after the .html() part (as Glen above suggests):

    $('#ctlPerson option:first').attr('selected', 'selected');

    I don't think you particularly need the .appendTo().

    If you still get stuck, let me know and I'll contact you directly.

  17. Thanks to you I think I finally found the way to fall in love with javascript. Keep writing that way!

  18. Thanks, but I figured it all out. I finally found out what my problem was. I was trying to make it easy to add more select boxes when needed too, to get some sort of flexible category/tagging thing. And I was having problems with cloning and appending complete select boxes, but that turned out to be a bug: http://dev.jquery.com/ticket/1087
    PrependTo & AppendTo simply strip out the select tag. No errors, but no results either. Thought I'd mention that here, for those that are fiddling with select boxes too at the moment.
    Thanks for this article, it helped a lot and it all works excellent now!

  19. Has anyone actually got this to work with the eBay style... I've tried but am having a really hard time figuring this out... I would LOVE to see a tutorial on this, if anyone has done it...

  20. While using this solution (thanks, by the way) I noticed IE6 complaining about attr('selected','selected'). The error is:

    Could not set the selected property. Unspecified Error.

    The reason this error occurs is because IE does not create the new html/dom until it gets back control from the script; first:option does not yet exist. You can get around this using the following:

    $('#Test').html(optionstring);
    setTimeout("$('#Test option:first').attr('selected','selected')",1);

    I'm not sure if there is a jQuery solution (I'm still learning) but I thought this might help someone else out.

Leave a Reply
Not required

CODE: Please escape code and wrap in <pre><code>, doing so will automatically syntax highlight