Showing posts with label filter. Show all posts
Showing posts with label filter. Show all posts

Jan 12, 2010

Cascading Select Boxes using jQuery

Today, we came across a need for a set of cascading select boxes to filter through a list of Organizations, Territories and Location. When I've come across this need in the past I tended to use ajax calls to load a new list into the select box based on the selection. While the ajax option is good for very large sets of data to keep the initial load time of the page down, it creates a few minor issues for smaller data sets.

  1. Returning a short list of options via ajax can be slow due to having to make a separate call to the server.
  2. Additional requests being sent to what may already to a taxed server
  3. There can be a good amount of server-side code that needs to be written to handle and respond to the ajax requests.

For our smaller data set we felt it would be more beneficial to start by loading all available options during page load and use jQuery to quickly filter and show only the options we need from the options already loaded into the browser. I came up with this function to do just this.

function cascadeSelect(parent, child){
 var childOptions = child.find('option:not(.static)');
 child.data('options',childOptions);
 
 parent.change(function(){
  childOptions.remove();
  child
   .append(child.data('options').filter('.sub_' + this.value))
   .change();
 })
 
 childOptions.not('.static, .sub_' + parent.val()).remove();
}

I was shocked at the ridiculously small amount of code needed to provide this functionality. After pre-building may page with a form containing the select boxes and added a class to each option in the child select to define which option from the parent it was associated with ("sub_1" where parents value is "1"), simply call the function with the parent and child defined as jquery objects:

cascadeForm = $('.cascadeTest');
orgSelect = cascadeForm.find('.orgSelect');
terrSelect = cascadeForm.find('.terrSelect');
locSelect = cascadeForm.find('.locSelect');
 
cascadeSelect(orgSelect, terrSelect);
cascadeSelect(terrSelect, locSelect);
And voila:
Organization:
Territory:
Location:

I've posted a full sample html at Snipplr. Feel free to comment and give suggestions there. As with all my code it's licensed as Creative Commons Attribution-Share Alike 3.0 Unported License. Feel free to consume and improve accordingly.

Update: ::face-palm:: In my joy of completing a task that seemed to good to be true, I posted this before realizing it was to good to be true. At this time I've only had a chance to test this code in Firefox. After an attempt to show it off, it appears to not work properly in WebKit browsers and maybe others. I will run it through the full gauntlet soon and do by best to ensure cross-browser compatibility for all browsers officially support by jQuery.

Update 2: After a little work and a better understanding of what doesn't work to "hide" options in browsers other than Firefox, I now have code that does just as I explained above but works cross-browser. I have updated the code above as well as the full example on Snipplr. Again, please feel free to give any feedback you might have.

Confirmed Working:
  • Firefox (3.6 RC1, 3.5, 3.0, 2.0, 1.5, 1.0)
  • IE (8, 7, 6 SP2, 6)
  • Safari 4
  • Opera (10, 9)
  • Chrome 4