Select boxes that limit other select boxes

This post is more than 2 years old.

That title probably doesn't do a great job of introducing the topic, but hopefully it will make more sense by the time the entry is done. A reader wrote me this week asking how to create select boxes that all share the same options. However, as soon as you pick an option in one, that option would then be removed from the other ones. A good example of this would be sorting data. Imagine you had N products. For each product you want to assign a ranking to it. Only one product can be 1, only one can be 2, and so on. Imagine that as you selected a particular rank, that rank was then removed from the others. Here's how I solved the problem using a little bit of ColdFusion and jQuery, my peanut butter and chocolate.

To begin, I'm going to mention an excellent jQuery plugin that I use whenever I'm doing SELECT box manipulation: Select box manipulation. This plugin supports a variety of nice methods that make it much easier to work with select boxes. Now let's look at the complete template.

<!--- fake data, a list of items and a list of options ---> <cfset items = "ColdFusion,PHP,Ruby,Beer,Star Wars"> <!--- Make a list from 1 to N ---> <cfset ranks = ""> <cfloop index="x" from="1" to="#listLen(items)#"> <cfset ranks = listAppend(ranks, x)> </cfloop>


<head> <script type="text/javascript" src=""></script> <script type="text/javascript" src="jquery/jquery.selectboxes.js"></script> <script> $(document).ready(function() {

//first, listen for any select change
$("select").change(function(e) {

	//did i have a previous value?
	var previous = $.data(this,'prev');

	//what did i pick?
	var chosen = $(this).val();

	//everyone else
	var everyoneelse = $("select").not($(this));

	//we loop over the rest and remove the option
	everyoneelse.each(function(x, el) {
		//only remove if i didnt pick the blank
		if(chosen != '') $(this).removeOption(chosen);
		//add back in previous
		if(previous) {
	//remember last choice
	$.data(this, 'prev', chosen);

}); </script> </head>


<form> <table> <cfloop index="idx" from="1" to="#listLen(items)#"> <cfoutput> <tr> <td>#listGetAt(items, idx)#</td> <td> <select name="item_#idx#"> <option value="">--Select One--</option> <cfloop index="r" list="#ranks#"> <option value="#r#">#r#</option> </cfloop> </select> </td> </tr> </cfoutput> </cfloop> </table> </body> </html>

Ok, let's tackle this. Normally I work bottom to top, but let's begin at the top just this once. Notice I've got some ColdFusion data there that generates a list. These items would be dynamic normally. Now if we go right back down to the bottom, you can see where I'm rendering them out in a simple table. (Don't hate me.)

The core of the page is the select box change handler. It does a few things. First off - we see if we had a previous value. This is important because if a select had previously "taken" rank 2, we need to "release" it back to the others. I'm using jQuery's data support for that.

Next I get the current value. After that, I then get the other selects. This is done using a not() function tied to a selector. I loop over the other selects and I do two things. First, if I actually picked something, I remove that option. Secondly, if I had a previous selection I add it back in and sort the options.

Finally I store the current selection as my previous value. And that's it. You can play with this yourself by hitting the big Demo button below.

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA

Archived Comments

Comment 1 by Sooraj posted on 8/27/2010 at 12:11 PM

Hi Ray,
Nice plugin, nice demo...

Comment 2 by Gary Funk posted on 8/27/2010 at 4:57 PM

Nice. Very nice. You just earned another nice toy. Now to find something you don't have.

Comment 3 by todd sharp posted on 8/27/2010 at 5:51 PM

Just a heads up FWIW - if you're trying to implement this method with a large number of select elements that contain a lot of options it will be very slow in Internet Exploder. Like everything else I guess, but this particular technique was so bad that I had to remove it from an app at work where IE is the standard browser...

Comment 4 by Christian Clark posted on 8/27/2010 at 6:42 PM

Would it be easy to amend the code to disable the previously used options rather than hiding them totally?

Comment 5 by Raymond Camden posted on 8/27/2010 at 7:01 PM

HTML option tags support a disabled property. You can try that.

Comment 6 by Brian posted on 8/27/2010 at 8:23 PM

Firebug doesn't keep up when you're looking at the HTML for this... after playing with the menus (and watching the state changes), I changed Beer to "Select One" -- Firebug only reflected the changes to option value attributes, but not the displayed value. I had to click the drop down for ColdFusion to verify that, yes, in fact the options display DID change. weird.

Comment 7 by Raymond Camden posted on 8/27/2010 at 8:26 PM

To be clear, you are saying something is odd with Firebug. Not my code. Right?

Comment 8 by Brian posted on 8/27/2010 at 8:30 PM

Yup... definitely Firebug. Your code is fine...