├── README.markdown
├── datasupplier.htm
├── datasupplier.php
├── index.htm
└── src
├── jquery.relatedselects.js
└── jquery.relatedselects.min.js
/README.markdown:
--------------------------------------------------------------------------------
1 | # jQuery Related Selects
2 |
3 | Demos @ [http://www.erichynds.com/examples/jquery-related-selects/](http://www.erichynds.com/examples/jquery-related-selects/)
4 | jQuery project page @ [http://plugins.jquery.com/project/related-selects](http://plugins.jquery.com/project/related-selects)
5 | Blog post/comments @ [http://www.erichynds.com/jquery/jquery-related-dependent-selects-plugin/](http://www.erichynds.com/jquery/jquery-related-dependent-selects-plugin/)
6 |
7 | jQuery Related Selects is a plugin that allows you to create any number of select boxes whose options are determined upon the selected value of another.
8 | You pass an array or object of select box names, and the select boxes will depend on each other in the order in which they are passed in.
9 |
10 | When a select box is changed an AJAX request is sent to the file specified in the onChangeLoad property, passing the selected value of each select box
11 | as parameters. The data must be returned in either JSON or HTML format. An
6 |
11 |
--------------------------------------------------------------------------------
/datasupplier.php:
--------------------------------------------------------------------------------
1 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/index.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Note that in examples 1-6, the file that supplies the data pauses for 1 second so you can see the loading messages.
86 |
87 |
Example 1
88 |
The state select is pre-populated, and the rest will populate based on preceding values. Each select is configured with a custom loading message, and the default option text is set to "Choose an Option".
89 |
108 |
109 |
Example 2
110 |
The state and county selects are pre-populated and legitimate values are selected. Since the 'County' select already has a selected option,
111 | the 'Town' select automatically populates. Individual selects do not have any custom settings. No defaultOptionText override.
112 |
132 |
133 |
134 |
Example 3
135 |
The state select is populated, and the HTML structure of the other three are completely empty when the page loads.
136 |
149 |
150 |
Example 4
151 |
Basic, just two selects.
152 |
163 |
164 |
Example 5
165 |
Using the onChange, onLoadingStart & onLoadingEnd callbacks.
166 |
179 |
180 |
Example 6
181 |
Using the DisableIfEmpty option & the onEmptyResult callback.
182 |
199 |
200 |
201 |
Example 7
202 |
Retreiving data in HTML format instead of JSON. This option gives you more control of the options, like the ability to add optgroups. View the data file.
203 |
213 |
214 |
215 |
216 |
217 |
--------------------------------------------------------------------------------
/src/jquery.relatedselects.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery Related Selects plug-in 1.1
3 | *
4 | * http://www.erichynds.com/jquery/jquery-related-dependent-selects-plugin/
5 | * http://github.com/ehynds/jquery-related-selects
6 | *
7 | * Copyright (c) 2009 Eric Hynds
8 | *
9 | * Dual licensed under the MIT and GPL licenses:
10 | * http://www.opensource.org/licenses/mit-license.php
11 | * http://www.gnu.org/licenses/gpl.html
12 | */
13 |
14 | (function($){
15 | $.fn.relatedSelects = function(opts){
16 | opts = $.extend({}, $.fn.relatedSelects.defaults, opts);
17 |
18 | return this.each(function(){
19 | new RelatedSelect(this, opts);
20 | });
21 | };
22 |
23 | var RelatedSelect = function(context, opts) {
24 | var $context = $(context), selects = [];
25 |
26 | // if the selects option is an array convert it to an object
27 | if($.isArray(opts.selects)){
28 | selectsToObj();
29 | }
30 |
31 | // make array of select names
32 | $.each(opts.selects, function(){
33 | selects.push(key);
34 | });
35 |
36 | // cache the options where the value is empty for each select before processing occurs.
37 | saveDefaultOptionText();
38 |
39 | // go through each select box & settings passed into options
40 | $.each(opts.selects, function(elem,o){
41 | var $select = $context.find("select[name='" + elem + "']"), // jquery ref to this select box
42 | $next = next(elem), // the select box after this one
43 | selectedValue = $select.val(); // currently selected value
44 |
45 | // extend element-specific options
46 | // set the defaultOptionText to whatever was passed in or the option where value is blank.
47 | o = $.extend({
48 | defaultOptionText: opts.defaultOptionText || $select.data('defaultOption')
49 | }, opts, o);
50 |
51 | // store the new default option text
52 | $select.data('defaultOption', o.defaultOptionText);
53 |
54 | // bind the change event
55 | $select.change(function(){
56 | o.onChange.call($select);
57 | process( $select, $next, elem, o );
58 | });
59 |
60 | // if there is already a selected option in this select and the next one is already populated, skip this iteration
61 | if(selectedValue && selectedValue.length > 0 && isPopulated($next)){
62 | return;
63 | }
64 |
65 | // process the select box upon page load
66 | process( $select, $next, elem, o );
67 | });
68 |
69 | function saveDefaultOptionText(){
70 | var $select, text;
71 |
72 | for(var x=1, len=selects.length; x 0 && value !== o.loadingMessage && $next){
88 |
89 | // reset all selects after this one
90 | resetAfter(elem);
91 |
92 | // populate the next select
93 | populate($select,$next,o);
94 |
95 | // otherwise, make all the selects after this one disabled and select the first option
96 | } else if($next){
97 | resetAfter(elem);
98 | }
99 | }
100 |
101 | function populate($caller,$select,o){
102 | var selectors = [], params;
103 |
104 | // build a selector for each select box in this context
105 | for(var x=0, len=selects.length; x' + o.loadingMessage + '');
114 |
115 | // perform ajax request
116 | $.ajax({
117 | beforeSend: function(){ o.onLoadingStart.call($select); },
118 | complete: function(){ o.onLoadingEnd.call($select); },
119 | dataType: o.dataType,
120 | data: params,
121 | url: o.onChangeLoad,
122 | success: function(data){
123 | var html = [], defaultOptionText = $select.data('defaultOption');
124 |
125 | // set the default option in the select.
126 | if(defaultOptionText.length > 0){
127 | html.push('');
128 | }
129 |
130 | // if the value returned from the ajax request is valid json and isn't empty
131 | if(o.dataType === 'json' && typeof data === 'object' && data){
132 |
133 | // build the options
134 | $.each(data, function(i,item){
135 | html.push('');
136 | });
137 |
138 | $select.html( html.join('') ).removeAttr('disabled');
139 |
140 | // html datatype
141 | } else if(o.dataType === 'html' && $.trim(data).length > 0){
142 | html.push($.trim(data));
143 | $select.html( html.join('') ).removeAttr('disabled');
144 |
145 | // if the response is invalid/empty, reset the default option and fire the onEmptyResult callback
146 | } else {
147 | $select.html( html.join('') );
148 | if(!o.disableIfEmpty){ $select.removeAttr('disabled'); }
149 | o.onEmptyResult.call($caller);
150 | }
151 | }
152 | });
153 | }
154 |
155 | function isPopulated($select){
156 | var options = $select.find('option');
157 | return (options.length === 0 || (options.length === 1 && options.filter(':first').attr('value').length === 0)) ? false : true;
158 | }
159 |
160 | function resetAfter(elem){
161 | var thispos = getPosition(elem);
162 | for (var x=thispos+1, len=selects.length; x0&&e!==f.loadingMessage&&a){n(c);s(b,a,f)}else a&&n(c)}}function s(b,a,c){var f=[],e=[];e=0;for(var t=g.length;e'+c.loadingMessage+"");d.ajax({beforeSend:function(){c.onLoadingStart.call(a)},complete:function(){c.onLoadingEnd.call(a)},dataType:c.dataType,data:e,url:c.onChangeLoad,success:function(l){var i=[],o=a.data("defaultOption");o.length>0&&i.push('");if(c.dataType==="json"&&typeof l==="object"&&l){d.each(l,function(u,v){i.push('")});a.html(i.join("")).removeAttr("disabled")}else if(c.dataType==="html"&&d.trim(l).length>0){i.push(d.trim(l));a.html(i.join("")).removeAttr("disabled")}else{a.html(i.join(""));c.disableIfEmpty||a.removeAttr("disabled");c.onEmptyResult.call(b)}}})}function w(b){b=b.find("option");return b.length===0||b.length===1&&b.filter(":first").attr("value").length===0?false:true}function n(b){b=p(b)+1;for(var a=g.length;b0&&w(f)||m(c,f,b,a)})};d.fn.relatedSelects.defaults={selects:{},loadingMessage:"Loading, please wait...",disableIfEmpty:false,dataType:"json",onChangeLoad:"",onLoadingStart:function(){},onLoadingEnd:function(){},onChange:function(){},onEmptyResult:function(){}}})(jQuery);
14 |
--------------------------------------------------------------------------------