Thursday, March 5, 2009

Cascaded HTML SELECT elements using JQuery

Many web applications at least from which i worked in demanded the existance of many select boxes stacked over each other. These HTML select boxes are used for filtering data underneath them.

But the idea is that in some cases, these ones are dependent on each other. One case can be a filter for cars that starts with types, then makes then trims and so on. In some of these filters the amount of overall filters data are not so large that they can all be retrieved with page once and then JS manipulation can be used to propagate between them.

I used to make this myself until i found myself fed up of doing things that should be generic. I looked for a plugin for JQUERY which i use as a JS framework in my application. Lucky me. i found one that does this cascading on two levels and then you can repeat on others until all get cascaded together.

The solution i found was that blog post
the solution proposed here was very nice but i found that i need to modify it somehow to be much more elegent and complete from my opinion. You may disagree with me in some modifications and it's your right to do so. Take the code and modify it as you wish

Before looking at my code, you can have a look at the post in order to be familiar with my solution.

Here is the code

cascadeLists: function(parentId, childId, callbackFunction){
var childOptions = $('#' + childId + ' option');
$('#' + parentId + childId).html(childOptions);

var parent = $('#' + parentId)[0];
if(parent.options[parent.selectedIndex].value == '')
$('#' + childId).html(childOptions.filter('[value=""]').clone());

$('#' + parentId).change(function(){
var parent = $('#' + parentId)[0];

var selectedOptionValue = '';
if (parent.selectedIndex > -1)
selectedOptionValue = parent.options[parent.selectedIndex].value;

if (selectedOptionValue == '')
$('#' + childId).html($('#' + parentId + childId + ' option[value=""]').clone());
else {
var childs = $('#' + parentId + childId + ' option[parent="'+selectedOptionValue+'"]');
if(childs.size() == 0)
$('#' + childId).html($('#' + parentId + childId + ' option[value=""]').clone());
$('#' + childId).html($('#' + parentId + childId + ' option[parent="' + selectedOptionValue + '"]').clone());

$('#' + childId).trigger("change");

if(callbackFunction != null) callbackFunction(selectedOptionValue);

In order to use this function, you will do as this example

<select id="parent"> <option value="1">xxx</option> <option value="2">xxx</option></select>

<select id="child"> <option parent="1" value="1">xxx</option> <option parent="1" value="2">xxx</option> <option parent="2" value="3">xxx</option></select>

just as your normal select boxes, but with additional IDs for each one of them and for the select box that have parent, each option state in its parent attribute the value of its parent

One Question will be: What if i want to add dummy option such as --select-- for both selects and whenever i choose this option in parent, child should be also this dummy one. Don't worry code handles this for you. If available this will be done. As for the dummy one, don't add to it a parent and let its value = ''

Now, just call the function and pass parameters:
  • parent select id
  • child select id
  • callbackFunction (optional) if you wish certain function to be called on any change to parent select, this function is called and pass to this function, the value of the option which was selected. Use this value to make any extra manipulation you want to do in the HTML page

Modification made are:
  • this method depend on option sent to it in order to show empty option on child, this isn't very nice in all cases, especially when dealing with internationalizations, in this case the data added here will have different text from a language to another. That's why i give you the ability to add empty option at the top of options and use it instead of generating one myself. that way you can choose what to write in this without changing in the JS Code The new logic is if there is an empty value option in child
  • Another option is needed is to call certain function whenever a change occurs on parent level and this function takes the new value, this way you can do any changes that was waiting such change like loading in Ajax some changes in page
  • One last change is that i see adding a parent attribute will be better than using sub_ and parent value

1 comment:

ClassicDresses said...

Once again great post. You seem to have a good understanding of these themes.When I entering your blog,I felt this . Come on and keep writting your blog will be more attractive. To Your Success!
my computer has something wrong!
maybe it does't update for a long time.

Classic Dresses
Classic Bridesmaid Dresses
Wedding Dresses with Sleeves