Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
jQuery.cascade : Cascading values from forms

 

First, get it here ...

Please leave commments/questions on jquery google group at : http://groups.google.com/group/jquery-en.

 

UPDATE: Fixed bug in ajax extension whereby it was holding a reference to previous data params. Also updated to work with jquery 1.2.6 in demo pack.

UPDATE 06-09-2008 : Breaking change: I inverted dependency from child==>parent to allow unique data sources for each target of a cascade. See distribution for details.

A common task is quickly fetching data to respond to changes on web forms. The canonical example is cascading select forms that provide options based on previous selections. However, there are numerous variants of this simple scenario that could be simplified using jquery's plugin pattern. Really, the goal is simple...when something happens on my page, get some data from somewhere and put in something else, with each item looking like I specify.

Being inspired by the awesome autocomplete plugin here, I adapted their compact code and event delegation pattern to create a simple but powerful plugin for cascading form results into their targets.

While the initial goal was simply cascading select lists and being able to chain them together, the event delegation made so simple in jquery quickly expanded the potential.

You can cascade from any kind of element into any other kind of element (for the most part). You can also provide extensions to the plugin easily enough to handle just about anything and it just weighs in at around 100 lines of code. Packed, it's 1.3 kB.

Events

There are only two events, loading.cascade and loaded.cascade triggered. You may specify what event will fire the cascade on the parent element. To bind to the cascade events, use the chained binding syntax common in jquery...this lets the control scale without munging up the options. For a great discussion of this technique see here and here .

 

Usage

Here are some examples on how to use it:

With all data being json, using the following structure:

{'when':'selectedValue','value':'itemValue','text':'itemText'}


   with static list on page:

$('#myChildSelect').cascade('#myParentSelect', {
list: [{'when':'A','value':'A1','text':'A1'},{'when':'B','value':'B1','text':'B1'}],
template: function(item) { return "<option value='" + item.value + "'>" + item.text + "</option>"; },
match: function(selectedValue) { return this.when == selectedValue; }
});

with ajax call (using .ext ):

$('#myChildSelect').cascade('#myParentSelect', {
ajax: '/my/url/action',
template: function(item) { return "<option value='" + item.value + "'>" + item.text + "</option>"; },
match: function(selectedValue) { return this.when == selectedValue; }
});

  

with chained cascading:

$('#myFirstChildSelect').cascade('#myParentSelect', {
ajax: {url: '/my/url/action' },
template: function(item) { return "<option value='" + item.value + "'>" + item.text + "</option>"; },
match: function(selectedValue) { return this.when == selectedValue; }
});

$('#mySecondChildSelect').cascade('#myFirstChildSelect', {
ajax: {url: '/my/url/action' },
template: function(item) { return "<option value='" + item.value + "'>" + item.text + "</option>"; },
match: function(selectedValue) { return this.when == selectedValue; }
});

 

add a firstOption for optional lists using the loaded.cascade event:  

jQuery("#myChildSelect").cascade("#myParentSelect",{    
timeout: 100,
list: myDataSource,
template: function(item) { return "<option value='" + item.Value + "'>" + item.Text + "</option>"; },
match: function(selectedValue) { return this.When == selectedValue; }
})
.bind("loaded.cascade",function(e,parent) { jQuery(this).prepend("<option value='empty' selected='true'>--Select--</option>");});

 

 

 

The download has a sample page with lots of different setups and usages. Please let me know if you find any bugs or questions. This is my first plugin for jquery so I may be missing some hidden jquery goodness to make the code more elegant.

 

I will try to get a working demo up soon.


Posted 05-25-2008 2:46 AM by Michael Nichols

[Advertisement]

Comments

Kalin Bogatzevski wrote re: jQuery.cascade : Cascading values from forms
on 05-29-2008 3:36 PM

Michael, you saved my day ;)

I am using a combination of jquery.autocomplete and jquery.validate and now i added your plugin to my application. Great!

I happened to find a small bug... when a user selects an entry from the first select box, and then re-selects.. the ajax call has 2 and more (for each new re-select) parameters with val=<value>.

Anyway, it is great! Integrated immediately!

Michael Nichols wrote re: jQuery.cascade : Cascading values from forms
on 05-29-2008 4:03 PM

@Kalin:

Glad you like it. I fixed the bug and updated the .zip files. Thanks for letting me know.

Mike

Kalin Bogatzevski wrote re: jQuery.cascade : Cascading values from forms
on 06-01-2008 4:56 AM

Michael, thanks for the update. It seems it needs more fix, as my IE7 returns an error in the plugin script: Line 29: Expected Identifier, ... and the debugger stops here:

//overwrite opt.ajax with required props (json,successcallback,data)

//this lets us still pass in handling the other ajax callbacks and options

Thanks again!

Michael Nichols wrote re: jQuery.cascade : Cascading values from forms
on 06-01-2008 6:15 PM

fixed

Kalin Bogatzevski wrote re: jQuery.cascade : Cascading values from forms
on 06-02-2008 5:18 AM

Great! Thanks! Works perfectly!

Robert Mayer wrote re: jQuery.cascade : Cascading values from forms
on 06-05-2008 10:22 AM

Hi and thanks for this great plugin!

But... how can i implement a selectbox which updates _two_ other selectboxes at one time? I don't get it.

Robert

Mike wrote re: jQuery.cascade : Cascading values from forms
on 06-05-2008 11:32 AM

@Robert-

Glad it helps. The update is just fired by an event (usually 'change') . Cascade is chainable, so simply chain together the children who will be listening to the parent select for updates to their html.

jQuery(document).ready(function()

{

jQuery("#morethanone")

.cascade("#morethanone_child",{

ajax: {url: 'data.js' },

template: commonTemplate,

match: commonMatch

})

.cascade("#morethanone_other_child",{

ajax: {url: 'data.js' },

template: commonTemplate2,

match: commonMatch

});

});

Robert Mayer wrote re: jQuery.cascade : Cascading values from forms
on 06-06-2008 4:02 AM

Thanks, Mike! But it does not work for me.

#morethanone_other_child has always the same elements as #morethanone_child. (I'm using two different ajax-urls.)

Robert

Kalin Bogatzevski wrote re: jQuery.cascade : Cascading values from forms
on 06-06-2008 4:16 AM

Hi, Mike!

I tried the same as Robert, and had the same result. The child_two had child_one results. Although with different ajax parameters.

Another question: how to initialize the 'selected' value? For example, when I need to display the same form, but with values that came from post/get.

The .bind adds the option, but with IE7 it is not selected. Maybe it's the same issue.

Thanks again!

Kalin

Dirk Bergstrom wrote re: jQuery.cascade : Cascading values from forms
on 06-09-2008 2:59 AM

Like Robert & Kalin, I need to cascade one select to two children, but with the added complication that one of the children also cascades to the other.  Like so:

Three selects, Primary (P), Secondary (S) & Tertiary (T)

P cascades to both S & T.

S Cascades to T.

When you select a value in P, it should populate S with all valid values, and T with values valid for all choices in S.  Then when the user selects something in S, T should be limited to just the valid values for that S selection.

I can get P=>S, P=>T like so (this is what Robert and Kalin want):

$("#P").cascade("#S" opts1);

$("#P").cascade("#T" opts2);

So when you change P, both S & T are populated correctly.

However, when I add this:

$("#S").cascade("#T" opts3);

Changing P populates both S and T, and then S immediately wipes out the values in T.

After a considerable amount of struggle (since I'm just learning jQuery), I came up with a solution.  I added another option, "noChainFrom".  You put the id of an element that should *not* trigger a change in this.  In the above example, it would be:

$("#S").cascade("#T" {..., noChainFrom: "P", ...});

Here's a patch:

@@ -64,7 +64,8 @@

                getList: function(select) { select.trigger("updateList", [opt.list]); }, //function to fetch datasource

                template: function(str) { return "<option value='" + str + "'>" + str + "</option>"; },//applied to each item in datasource

                match: function(selectedValue) { return true;}, //'this' is the js object, or the current list item from 'getList',

-                event: "change.cascade"

+                event: "change.cascade",

+                noChainFrom: null,

    }, opt);

    if($.ui.cascade.ext) {

@@ -87,17 +88,21 @@

                        }

                }

-                $(this).bind(opt.event,function() {

+                $(this).bind(opt.event,function(e, evtSource) {

                        self.trigger("loading.cascade",[container[0]]);

                        var selectTimeout = $.data(this, "selectTimeout");

                        if(selectTimeout) { window.clearInterval(selectTimeout); }

                        $.data(this, "selectTimeout", window.setTimeout(function() {

-                                        self.trigger("cascade");

+                                        self.trigger("cascade", [evtSource]);

                        }, opt.timeout));

                })

-        .bind("cascade", function() {

+        .bind("cascade", function(evt, evtSource) {

+          if (opt.noChainFrom && evtSource == opt.noChainFrom) {

+            // We're not supposed to chain if the event came from this source

+           return;

+          }

          self.one("updateList", function(e, list) {

            list = $(list)

              .filter(function() { return opt.match.call(this, self.val()); })

@@ -114,7 +119,8 @@

                        self.trigger("loaded.cascade",[container[0]]);//be sure to fire even if there are no data

                        if( container.is(":input") ) {

-                                container.trigger("change.cascade");

+              // Let the target know that we've changed it

+              container.trigger("change.cascade", [e.target.name]);

                        }

          });

Kalin Bogatzevski wrote re: jQuery.cascade : Cascading values from forms
on 06-09-2008 4:53 AM

Hi, Dirk!

Thanks for your proposal. I have a question concerning the opts. You were using:

$("#P").cascade("#S" opts1);

$("#P").cascade("#T" opts2);

Does this mean that those opts' functions used should be different?

Here's my case now: I got 3 boxes too. The 1st and the 3rd box are initialized with some values taken from database (with a php function). When an item from 1st is selected it should cascade 2nd box and the 3rd. Default values should be 'selected' with .bind, but it doesn't work with me but the first returned by ajax is becoming the current option.

It is also necessary that I get the current value from the 1st box to prepare the 3rd. I tried with jquery..val(), then with get(0).. no proper result.

Here's an example:

$("#user_place").cascade("#user_school",{

ajax: {url: \'/rpc.php?call=schoolsel&r=y\' },

template: commonTemplate,

match: commonMatch

})

.bind("loaded.cascade",function(e,target) {

$(target).prepend("<option value=\'\' selected=\'true\'>All schools</option>");

});

$("#user_school").cascade("#schoolLeavingYear",{

ajax: {url: \'/rpc.php?call=yearsel\' },

template: commonTemplate,

match: commonMatch

})

.bind("loaded.cascade",function(e,target) {

$(target).prepend("<option value=\'\' selected=\'true\'>All years</option>");

});

This does a proper 1 to 2 to 3 relation. When I added a 1 to 3 relation - the values in 2 become those that should be in 3.

I hope you understand my mess. Thanks.

Kalin.

Mike wrote re: jQuery.cascade : Cascading values from forms
on 06-09-2008 12:13 PM

@Kalin,@Dirk

I am refactoring the component to handle this scenario. I'll post it in a few days.

Mike

Mike wrote re: jQuery.cascade : Cascading values from forms
on 06-09-2008 12:34 PM

@Kalin,

In IE I have to make the binding look like this and it works just fine. Not that I have to explicitly set 'selected=true' directly on the element.

jQuery(document).ready(function()

{

jQuery("#optional").cascade("#optional_child",{

list: list1,

template: commonTemplate,

match: commonMatch

})

.bind("loaded.cascade",function(e,target) {

jQuery(this).prepend("<option value='empty' selected='true'>--Select--</option>");

jQuery(this).find("option:first")[0].selected = true;

});

});

Michael Nichols wrote re: jQuery.cascade : Cascading values from forms
on 06-09-2008 4:05 PM

@Robert,@Kalin,@Dirk:

Cascade has been updated to permit multiple data sources. See notes please

Kalin Bogatzevski wrote re: jQuery.cascade : Cascading values from forms
on 06-09-2008 9:17 PM

Thanks, Michael!

I've just updated all my scripts to the new version.

Fixed all what I needed.

For the initialization I used php function which was making the first option lists (before ajax) and taking the parameters from the submit form.

Also thanks for the IE fix. Will have this in mind in the future.

Kalin.

kab wrote re: jQuery.cascade : Cascading values from forms
on 06-17-2008 11:26 AM

I am just new to jquery and this is just what I was looking for. I have it working, building the parent and dependent child based on ajax/sql calls to a db.

Now I want to use the parent and child selected to build a table of results.

But... being the newbie that I am - how do I get the value of the selected? and then get those values into a php/ajax command.

Thanks! Learning alot.

Michael Nichols wrote re: jQuery.cascade : Cascading values from forms
on 06-17-2008 11:52 AM

@Kab-

To get the value from a form element use jQuery('#myFormId') .val()

As far as the php command I can't help you there. Try a php forum.

kab wrote re: jQuery.cascade : Cascading values from forms
on 06-17-2008 12:04 PM

Sorry - didn't make myself clear. - Where do I use it? In your example - where would I put an alert(('#myFormId') .val())? I see your other alert - but it just says - yep... done.

Michael Nichols wrote re: jQuery.cascade : Cascading values from forms
on 06-17-2008 3:46 PM

>Where do I use it?

Use what...cascade? I can't really help with that.

What are you trying to accomplish?

The sample index.html has example usages for the component.

kab wrote re: jQuery.cascade : Cascading values from forms
on 06-18-2008 10:56 AM

your sample index.html is great. It shows me almost everything I need to know.

In the example "simple ajax (in ext)" when the child list is updated, you call complete:function(){alert(;my list is updated');}

How, when someone has selected an item from the child list would I create an alert("you just selected XXX")

thanks

Michael Nichols wrote re: jQuery.cascade : Cascading values from forms
on 06-18-2008 11:58 AM

Ah...okay

The child list doesn't have any events registered by cascade, so to do this you just need to:

$('#myChildList').change(function(){ alert($(this).val() + ' is my child value');});

I am just binding an change event handler onto the child list. This isn't really an cascade issue, but more registering events with html elements.

hope it helps

kab wrote re: jQuery.cascade : Cascading values from forms
on 06-19-2008 4:40 AM

thanks!

kab wrote re: jQuery.cascade : Cascading values from forms
on 07-11-2008 7:43 AM

Me again :)

Been playing with this somemore. Have it working great - but of course I want to get even fancier.  I create the initial parent select list from a db call.  Then I want to cascade off of that created parent list.

I am having trouble "binding" the children cascade off of that parent. This is what I have/want and which is not working, and not coming up with any errors.

Thanks

case "project":

 $.getJSON("selects.php",{project:"%"}, function(json)

{

options += '<option value="%" selected>All Projects</option>';

for (i = 0; i < json.length; i++) {

  options += '<option value="'+json[i]['project']+'">'+json[i]['project']+'</option>';                

}

$("#view_project").empty();

$("#view_project").append('<select id="select_project" name="select_project" size="'+dropsize+'">' +options+ '</select>');

$("#select_project").bind("click", function(){

  alert("DEBUG - clicked project="+$(this).val());

****do the cascade here****

---------

jQuery("#experiment").cascade("#select_project",{

ajax: {url: 'selects.php'},

 template: commonTemplate,

 match: commonMatch

})

.bind("loaded.cascade",function(e,target) {

jQuery(this).prepend("<option value='empty' selected='true'>--Select Experiment--</option>");

jQuery(this).find("option:first")[0].selected = true;

});

-----------

 });                

})

               break;

Mike wrote re: jQuery.cascade : Cascading values from forms
on 07-11-2008 12:09 PM

@kab

What is Firebug telling you? Is the XHR call happening ? What is the behaviour of the controls after you change the 'experiment' control?

kab wrote re: jQuery.cascade : Cascading values from forms
on 07-14-2008 12:50 PM

thanks - seems I hadthe cascade call in the wrong place. works great!

Is there anyway to change the select size?

kab wrote re: jQuery.cascade : Cascading values from forms
on 07-15-2008 5:38 AM

answred by own question:

jQuery(this).html(options).attr({ size: '8' });

thanks again - does everything I need.

kab wrote re: jQuery.cascade : Cascading values from forms
on 07-15-2008 5:40 AM

Spoke too soon. That doesn't seem to work. It repeats the parent select. hmmm.

Tomas wrote re: jQuery.cascade : Cascading values from forms
on 07-25-2008 10:38 PM

Hi,

I am new to both jquery and cascade. I have been doing it for a few hours now. I am trying to send via ajax the value of the selected Index, using $('#id_state').val(). I doesn't work.  See code snippet below.

Please help.

Tomas

-------------------------------------

jQuery("#id_county").cascade("#id_state",{

   ajax: { url: '/cgi-bin/report_handler_jquery_test.pl?mode=ajax&elem=id_state' + '&selIndex=' + $('#id_state').val()},

   template: function(item) { return "<option value='" + item.value + "'>" + item.text + "</option>"; },

   match: function(selectedValue) { return this.when == selectedValue; }

});

Tomas wrote re: jQuery.cascade : Cascading values from forms
on 07-26-2008 2:03 AM

@Tomas,

What does Firebug tell about the ajax call being made? In other words, what doesnt work?

Kevin wrote re: jQuery.cascade : Cascading values from forms
on 09-03-2008 5:54 AM

Thanks

I am new to both jquery and cascade.

This plugin is works perfectly.

but i still got a bit problem.

when i use this in member data modify page.

how can i give the two dropdown boxes  default value

i have tried set value in javascript and echo "selected" to option in php on first box.

both can correctly make the option that i want as default select item.

but seems can't trigger second box.

if i dont really click on the first box or just only set value or echo "selected" in option.

the second box still empty.

thanks

and sorry for my broken English.

Sergio wrote re: jQuery.cascade : Cascading values from forms
on 09-05-2008 5:06 PM

I can only say: YOU ARE A GENIOUS.

Marc Fathauer wrote re: jQuery.cascade : Cascading values from forms
on 09-09-2008 2:56 PM

Any thoughts on how you could make it to work using radio buttons as  the initial selction criteria? Seems to only function if the first item has a unique ID, making it seemingly impossible to use radio buttons. I tried using class instead but thtat failed

Mike wrote re: jQuery.cascade : Cascading values from forms
on 09-14-2008 11:55 PM

@Marc,

I haven't tried this with radio buttons, but I am not sure I understnad why unique class names or ids wouldn't work...Radio buttons are grouped together by their 'name' attribute in most browsers I believe. I would try the id thing.

@Kevin,

Do you have a sample page I can see to see what is wrong?

Mike wrote re: jQuery.cascade : Cascading values from forms
on 09-14-2008 11:57 PM

Please use the jquery forums at groups.google.com/.../jquery-en with 'cascade' in the subject for support on this comment so we can create a repository for these issues.

Thanks!

Mike

Comments are closed on this post.

Ez wrote re: jQuery.cascade : Cascading values from forms
on 10-07-2008 12:55 AM

can you use checkboxes instead of an option? How? I have changed the code to use checkboxes and the selections come up but I can't see the values that go to them?

Bruce wrote re: jQuery.cascade : Cascading values from forms
on 11-04-2008 6:05 PM

Is there any way to enable optgroups with these selects?

Bruce wrote re: jQuery.cascade : Cascading values from forms
on 11-04-2008 6:07 PM

I am developing an application that allows users to edit existing data. i would like to use the cascading selects, but im not sure how to set selected elements in a series of cascaded selects so they all show up when the form is first displayed

Mike wrote re: jQuery.cascade : Cascading values from forms
on 11-06-2008 2:33 PM

@Bruce-

How would you normally present data in a form on load?  

Bruce wrote re: jQuery.cascade : Cascading values from forms
on 11-07-2008 4:58 PM

lets say i have a cascade of 3 lists: country, state, city. if they had previously selected country US, state CO, and cities of Denver, Englewood, and lakewood, when i go back to the form to edit i would like to show the 3 lists with those values selected. that way they would be able to add or remove options.

syncml wrote re: jQuery.cascade : Cascading values from forms
on 12-06-2008 11:51 PM

hi,

it's a nice plugin!

But if  i want to fetch the first select by ajax on page is loaded,that means the first select is dynamic, how can i implement ? or what's the function in jquery.cascade.js.

thanks

LowOrbit wrote re: jQuery.cascade : Cascading values from forms
on 12-15-2008 11:25 PM

Hi, thanks for this, it works really well for me.  One question however:

I have two combos, and upon form load the first combo is populated as per usual (nothing to do with cascade), and the second combo is empty.  When a value in the first combo, cascade is correctly showing linked child values in the second combo.

How can I tell cascade to trigger an update so that upon form load, the child combo is updated with related items?

Thanks!

Mike wrote re: jQuery.cascade : Cascading values from forms
on 12-16-2008 12:33 AM

Please post questions regarding the cascade on the jquery group at groups.google.com/.../jquery-en

@LowOrbit - just fire a 'change' event on the parent combo box during your $.ready() handler.

[AJAX] jQuery plugin cascade ???????????????????????? by json | ????????? - ???????????? - ???????????? - ???????????? - AppleBOY wrote [AJAX] jQuery plugin cascade ???????????????????????? by json | ????????? - ???????????? - ???????????? - ???????????? - AppleBOY
on 12-18-2008 10:27 PM

Pingback from  [AJAX] jQuery plugin cascade ???????????????????????? by json | ????????? - ???????????? - ???????????? - ???????????? - AppleBOY

James wrote re: jQuery.cascade : Cascading values from forms
on 01-31-2009 6:36 PM

I am new to JQuery and your cascading dropdown was exactly what I was looking for.  After formatting my data in JSON I have tested out the Chained example and it ONLY WORKS in Firefox and NOT IE.

I am attempting to load the data from two external files, while your example loads the second data set from a static var.

Is there a further step necessary to get this to work in IE?

I have my working example at: jamestilberg.com/jquery

Any help would be appreciated!  :)

James wrote re: jQuery.cascade : Cascading values from forms
on 02-03-2009 11:05 AM

Hey Mike...James here again.  Now that I've worked through some of the basics, I would like to know how easy it would be to accommodate a JSON file in a bit of a more efficient structure using arrays rather than a simple value pairs.

IE.: You have designed around this structure:

{'when':'selectedValue','value':'itemValue','text':'itemText'}

Whereas after some testing, I've realized the data sizes would become rather huge rather quickly.

I'm proposing a JSON structure such as:

{

   "Country1": [

       {

           "Region1": [

               "City1",

               "City2",

               "City3"

           ],

           "Region2": [

               "City1",

               "City2",

               "City3"

           ]

       }

   ]

}

The idea would be for a separate JSON file for each country (now that we've got dynamic URLs working).  Of course this simplified structure would require some parsing and reformatting to fit the structure you have used for the .CASCADE plugin.

My problem is, since I'm so new to all this, I have no idea where in the code to begin looking at how to take my imported JSON file, and then do the work on it to change it into your format.

Could you offer some insight on this?

Thanks,

James

Httpcode wrote ASP.NET Control Toolkit – JQuery Equivalents
on 02-04-2009 3:48 PM
Phil wrote re: jQuery.cascade : Cascading values from forms
on 04-03-2009 8:57 AM

An initial load option on a cascade would be great, like I have a form which the first values are dynamic and not hard coded so I  can't  use your solution yet.

Any Help please?

Chalalo Land wrote Controles JQuery equivalentes a Ajax Control Toolkit
on 05-26-2009 10:23 AM

Que tal, de nuevo navegando y relacionado con mi antiguo post, encontré una página recopilatoria

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)