Tech Stuff

Working With Selections (Geeky)

For a project at The Job recently, I needed to do the time-honored trick of changing the contents of a select box based on the selection chosen in another. Straightforward enough, I guess. I based mine on an idea of sabithpocker on Stack Overflow, which clones all of the options, then filters them based on the criteria given — in this case, the value of the selected “trigger” index.

But I needed something more extensible once it was suggested in a meeting that we needed two filtered drop-downs based on the first. This is what I came up with.





You can look at the source for all the relevant code, but this salient points are:

  • You must be using jQuery
  • Assign the function to the id of the controlling dropdown. In this case, to make it simple, I called it #trigger.
  • Each item in that select box needs a clear and consistent value. Numbers work, so I used (blank), 1 and 2.
  • The other select boxes, the ones that are controlled, should have a distinctive classname. That way, you only control the ones you want to switch and not any others somewhere else on the page that aren’t involved in this part of the selection. I used “switchable.” Notice the last select box doesn’t have it, and is therefore ignored.
  • Each item in the other select boxes needs to have classnames based on the name, and incorporating the matching value from the controller. That sounds complex. Here is how it breaks out:

    <select id="" class="xlarge switchable" name="category">
    <option value="1" class="category_1">Uncategorized</option>
    <option value="2" class="category_1">Freshman Studies</option>
    <option value="3" class="category_1">Ministry and Mission</option>
    <option value="5" class="category_1">Technology</option>
    etc.
    </select>

    This controlled selectbox, which has items pertinent to the first selector in the controller has the class “switchable,” and the name “category.” So the individual select items all have the class “category_1”.

    If your second selectbox is controlled by the second item in the controller, and is named “issuer,” each option there will be of class “issuer_2”.

    This sounds all hairy and confusing, but chances are you’re generating this automatically from a database anyway, right?

The controlling code looks like this. This isn’t strictly necessary, but to get it to work in WordPress I needed to no-conflict the jQuery element.

var $j = jQuery.noConflict();

Then, when the document is fully loaded,

$j(document).ready(function(){

Bind the function to the #trigger <select> element, whenever it changes:

$j("#trigger").change(function() {

Then, if it’s the first time around, grab all of the <option> elements from the <select> boxes with class “switchable,” and clone them into $(this).

if ($j(this).data('options') == undefined ) {
$j(this).data('options',$j('select.switchable option').clone());
}

Then, assign whatever is selected in the trigger <select> box to the variable “id” (or whatever).

var id = $j(this).val();

This was tricky. When we iterate through each <select>, $(this) will be broken because it’s in a new scope. I could have learned to use $j.proxy, but in this case at least it was easier to store it in another variable for use inside the block.

var that = this;

Now, we’re going to iterate through each <select> of class “switchable.”

$j("select.switchable").each(function() {

Grab its name (I probably could have one-lined this but it’s easier to explain this way).

var thisname = $j(this).attr('name');

Then, bolt together the class selector ‘.’, the name of the <select> box (e.g., category), an underscore, and the id (what was selected in the trigger), and filter all of the <options> we cloned a little earlier looking for the classname that matches — something like ‘.category_1’.

var theseoptions = $j(that).data('options').filter( '.' + thisname + '_' + id );

Then, take the <select> we’re working with (the one named “thisname”) and replace whatever is inside it with the matching list of <option>s.

$j(this).html(theseoptions);
});
});

The first time around, all the <option>s will show for all the <select>s, which isn’t what we want. We want them to be blank until the user picks one. So we fire it off once to display the correct <option> group, and then close out the function block.

$j('#trigger').trigger('change');
});

By assigning the right <select> names and <option> classes, you can control any number of <select> elements from a single master.

Tom
Tom McGee has been building web sites since 1995, and blogging here since 2006. Currently a senior developer at Seton Hall University, he's also a freelance web programmer and musician. Contact him if you have the need for a blog, web site, redesign or custom programming!

Leave a Reply

Your email address will not be published. Required fields are marked *