3

All,

I have two selects that look like this:

<select name='input_34' id='input_1_34' class='small gfield_select' tabindex='1' > <option value='29' >Alabama</option> <option value='34' >Alaska</option> <option value='42' >Arizona</option> .... <select name='input_13' id='input_13' class='small gfield_select' tabindex="2"> <option value='-1' selected='selected'>Select a base</option> <option class="level-0" value="29">Alabama</option> <option class="level-1" value="30">&nbsp;&nbsp;&nbsp;Anniston Army Depot</option> <option class="level-1" value="333">&nbsp;&nbsp;&nbsp;Fort Rucker</option> <option class="level-1" value="32">&nbsp;&nbsp;&nbsp;Maxwell-Gunter AFB</option> <option class="level-1" value="33">&nbsp;&nbsp;&nbsp;Redstone Arsenal</option> <option class="level-0" value="34">Alaska</option> <option class="level-1" value="35">&nbsp;&nbsp;&nbsp;Eielson AFB</option> <option class="level-1" value="36">&nbsp;&nbsp;&nbsp;Elmendorf AFB</option> <option class="level-1" value="37">&nbsp;&nbsp;&nbsp;Fort Greely</option> <option class="level-1" value="38">&nbsp;&nbsp;&nbsp;Fort Richardson</option> <option class="level-1" value="39">&nbsp;&nbsp;&nbsp;Fort Wainwright</option> <option class="level-1" value="40">&nbsp;&nbsp;&nbsp;USCG ISC Kodiak</option> <option class="level-1" value="41">&nbsp;&nbsp;&nbsp;USCG Juneau</option> <option class="level-1" value="42">&nbsp;&nbsp;&nbsp;USCG Ketchikan</option> <option class="level-0" value="43">Arizona</option> 

What I want to do is select a state in the first dropwown, and then remove all the options in the second dropdown, except those listed under the selected state.

What I've done so far is determine the selected state from the first dropdown, then get the index for where that option is in the second dropdown. How should I proceed from there? I was thinking about using .next() to go through each option with class .level-1, stopping at .level-0. Once I have that I can use .remove() to remove all other options except those.

Here is my code so far:

jQuery(document).ready(function(){ jQuery('#input_1_34').bind('change', function() { //get selected value from drop down var selectedValue = jQuery("#input_1_34").val(); //hide everything but bases for the selected state //jQuery("#input_13 option[value=" + selectedValue + "]").next().remove(); selectedIndex = jQuery("#input_13 option[value=" + selectedValue + "]").index(); alert (selectedIndex); }); }); 
6
  • 1
    My first thought is I think you're making this problem more difficult by the way you have this set up. Does the second select control have to have all those options to start out with? It seems like disabling that control until a selection in the first one is made, then filling it with the appropriate options would be easier, but maybe there's some kind of user interaction flow that wouldn't allow this? Commented Jul 4, 2011 at 20:37
  • I agrre that you could make your life easier by changing the html, look at my answer if it's what you wanted to do! Commented Jul 4, 2011 at 20:50
  • @kinakuta: @user6641 should do it the way it currently is for the sake of graceful degradation. Though I'd highly recommend <optgroup> elements as I have in my updated answer. Commented Jul 4, 2011 at 21:13
  • @patrick_dw From a strictly progressive enhancement/graceful degradation perspective I can see what you mean, but from a ui perspective, having two controls set up this way isn't ideal. Commented Jul 4, 2011 at 21:18
  • @kinakuta: Yeah, I'd think it would be a good idea to hide (or remove) the second one until it needs to be populated. Commented Jul 4, 2011 at 21:20

3 Answers 3

6

EDIT: Updated answer.

I'd highly recommend using <optgroup> elements to group the bases in each state.

That way you won't need all the &nbsp; to create indentation, and it gives a nice look when you set the state as the label.

<select name='input_13' id='input_13' class='small gfield_select' tabindex="2"> <option value='-1' selected='selected'>Select a base</option> <optgroup class="level-0" value='29' label="Alabama"> <option class="level-1" value="30">Anniston Army Depot</option> <option class="level-1" value="333">Fort Rucker</option> <option class="level-1" value="32">Maxwell-Gunter AFB</option> <option class="level-1" value="33">Redstone Arsenal</option> </optgroup> <optgroup class="level-0" value="34" label="Alaska"> <option class="level-1" value="35">Eielson AFB</option> <option class="level-1" value="36">Elmendorf AFB</option> <option class="level-1" value="37">Fort Greely</option> <option class="level-1" value="38">Fort Richardson</option> <option class="level-1" value="39">Fort Wainwright</option> <option class="level-1" value="40">USCG ISC Kodiak</option> <option class="level-1" value="41">USCG Juneau</option> <option class="level-1" value="42">USCG Ketchikan</option> </optgroup> <optgroup class="level-0" value="43" label="Arizona"> <option class="level-1" value="44">USCG whatever</option> <option class="level-1" value="45">USCG whatever</option> </optgroup> </select> 

It also simplifies your code a little, since you can select all the children of the optgroup.

Example: http://jsfiddle.net/asBSU/3/

jQuery(document).ready(function() { var clone_select = $('#input_13').clone(); jQuery('#input_1_34').bind('change', function() { var selectedValue = jQuery("#input_1_34").val(); var clone_subset = clone_select .find('optgroup[value="' + selectedValue + '"] > option') .clone(); $('#input_13').empty().append(clone_subset); }); }); 

I'd imagine you could get rid of all those level-n classes too.

We could even simplify and clean up the code a bit more like this:

Example: http://jsfiddle.net/asBSU/4/

jQuery(document).ready(function() { var clone_groups = $('#input_13 > optgroup').clone(); jQuery('#input_1_34').bind('change', function() { clone_groups.eq( this.selectedIndex ) .children() .clone() .appendTo( $('#input_13').empty() ); }); }); 

This is because the index of each <option> in the first <select> will correspond with the index of the desired <optgroup> in the cloned <select>.



Original answer:

Use the clone()[docs] method to keep a clone the entire <select> that has the long list.

When a value is selected from the first, do the following:

Then from the select that's on the page, use:

Example: http://jsfiddle.net/XrFr7/2/

jQuery(document).ready(function(){ var clone_select = $('#input_13').clone(); jQuery('#input_1_34').bind('change', function() { var selectedValue = jQuery("#input_1_34").val(); var clone_subset = clone_select.find('option') .filter('[value="' + selectedValue + '"]') .nextUntil('.level-0') .clone(); $('#input_13').empty().append( clone_subset ); }); }); 

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, thank you! This worked great... and I appreciate the helpful explanation of the functions you used that I was not aware of, such as clone() and nextUntil(). It seems like with jQuery they've thought of everything. I really appreciate this. I just purchased a book from Sitepoint, jQuery - from Novice to Ninja. Hopefully that will get me up to speed so I can start figuring these things out like you.
Also, as I stated above optgroup sounds great, but the dropdown is generated by wordpress. I don't want to edit the core function as I'm nervous that it will break the next time I upgrade wordpress.
1

You could use nextUntil() and do like this:

var allOptions = $("#input_13 option"); jQuery('#input_1_34').bind('change', function() { //get selected value from drop down var selectedValue = jQuery("#input_1_34").val(); $('#input_13').html('').append(allOptions); selectedOptions = $("#input_13 option[value=" + selectedValue + "]").nextUntil('.level-0').andSelf(); $('#input_13').html('').append(selectedOptions); }); 

EDIT- i changed the answer to allow the user to choose more options

Look at the fiddle here: http://jsfiddle.net/QGCh4/2/

2 Comments

But what happens when you want to change states? You've destroyed all the original option elements.
You could save all the options and then bring them back - i edit the post to reflect this. Anyway you'd better change your markup!
0

I agree with kinakuta, you're making this too difficult. If you really want to use this flow, you could try something like:

jQuery(document).ready(function() { jQuery('#input_1_34').bind('change', function() { //get selected value from drop down var selectedValue = jQuery("#input_1_34").val(); var removing = true; jQuery('#input_13 option').each(function() { if (jQuery(this).hasClass('level-0')) { removing = !(jQuery(this).val() == selectedValue); } if (removing) { jQuery(this).hide(); } else { jQuery(this).show(); } }); }); }); 

Which loops though all of the elements and hides/shows them. If you remove the elements you have to repopulate the array.

1 Comment

You can't hide <option> elements in some browsers.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.