Chain select (AJAX)

Sometimes you have two select boxes and you want to fill the second one with options depending on the user's selection in the first box. There are a few ways to do this. This one uses AJAX.

Here's what I'm talking about:

The HTML looks like this:

HTML
<form method="post" action="#">
<p><label>country: <select id="country" name="country">
<option value="United Kingdom">United Kingdom</option>
<option value="United States">United States</option>
<option value="Australia">Australia</option>
<option value="Japan">Japan</option>
</select></label>
<label>city: <select id="city" name="city">
</select></label></p>
</form>

The second box is empty because the javascript fills it. The javascript looks like this:

javascript
var request = false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
request = false;
}
}
@end @*/
if (!request && typeof XMLHttpRequest != 'undefined') {
request = new XMLHttpRequest();
}

function fillSelect(country) {
var url = "csa_ajax.php?country=" + escape(country);
request.open("GET", url, true);
request.onreadystatechange = go;
request.send(null);
}

function go() {
if (request.readyState == 4) {
if (request.status == 200) {
var response = request.responseText;
var list=document.getElementById("city");
var cities=response.split('|');
for (i=1; i<cities.length; i++) {
   var x=document.createElement('option');
   var y=document.createTextNode(cities[i]);
   x.appendChild(y);
   list.appendChild(x);
   }
  }
 }
}

function initCs() {
var country=document.getElementById('country');
country.onchange=function() {
 if(this.value!="") {
  var list=document.getElementById("city");
  while (list.childNodes[0]) {
list.removeChild(list.childNodes[0])
}
  fillSelect(this.value);
  }
 }
 fillSelect(country.value);
}

This is called onload like this:

javascript
window.onload=initCs;

The first part (before the first function) sets up the XMLHttpRequest() object. The initCs() function loads the second select box onload and sets an onchange event for the first box. Onchange, the fillSelect() function is called. The selected option is sent as a variable to a PHP page, 'csa_ajax.php', which looks like this:

PHP
<?php
function doIt($country) {
switch ($country) {
case "United Kingdom":
return array('London','Manchester','Birmingham','Liverpool','Edinburgh','Cardiff','Belfast');
break;
case "United States":
return array('Washington DC','New York','Los Angeles', 'Chicago');
break;
case "Australia":
return array('Canberra','Melbourne','Sydney', 'Brisbane');
break;
case "Japan":
return array('Tokyo','Osaka','Fukuoka','Sendai','Sapporo');
break;
 }
}

$country=@$_GET['country'];
$cities=doIt($country);
foreach ($cities as $city) {
echo '|'.$city;
}
?>

That takes the value of the selected option and chooses the appropriate array for it. This would often be done by calling data from a database, but for convenience, I've used a switch(). The last bit echoes each of the items in the array preceded by '|' for the javascript to split up into individual items. The go() function takes the output from the PHP page, breaks it down, makes new text nodes out of each item, appends them to new option nodes and adds the option nodes to the select box.

Comments

#1
2007-10-24 JSmoke says :

This works slick. Here's a little variation that would make an <option> become <option selected> based on the first value.

So you could look up the first value entered in your database and then make that selected in your second select menu. You'd have to return the value of the <option id> from your database.

function go() {
if (request.readyState == 4) {
if (request.status == 200) {
var response = request.responseText;
var list=document.getElementById("city");
var curCity = document.getElementById(response);
curCity.selected = true;
}
}
}

function initCs() {
var memberLogin=document.getElementById('country');
memberLogin.onchange=function() {
if(this.value!="") {

fillSelect(this.value);
}
}
fillSelect(country.value);
}

#2
2007-11-05 AURILEIDE says :

It doesn´t work on IE. Pity!!!

#3
2007-11-05 BonRouge says :

AURILEIDE,
I've just checked this page on IE6 and IE7, and as far as I can see, it works fine. What seems to be the problem?

#4
2007-11-05 JSmoke says :

Maybe he's referring to my Comment. It's not working in IE, trying to debug it. Not sure why, it's not very different from your original.

#5
2007-11-05 JSmoke says :

It works for the most part, but there's something fishy with IE's cache of the results from the database.

#6
2007-11-06 JSmoke says :

Sorry, not trying to turn this into a forum, but the problem was with IE using the cache. You need to force it to grab new data from the DB on every onchange event.

Here's some methods, using the header PHP commands worked for to get this script working.

http://www.greenash.net.au/posts/thoughts/an-ie-ajax-gotcha-page-caching

#7
2007-12-15 /\/\ongoose says :

Hello,

Just wondering if there is a way to store the arrays into a database...and then say make a form to where you could add to the arrays.

Like say you wanted to add a city to the United States...

#8
2008-01-09 Nick says :

i too, would also like to know if its possible to have the cases and arrays outputted by a database?

#9
2008-01-11 BonRouge says :

/\/\ongoose / Nick,
Yeah, it's easy enough to use a database to do this. I would have done that here, but I just couldn't be bothered.
The query to the database would look something like this:<?php

$country=@$_GET['country'];
$q = mysql_query("SELECT city FROM cities WHERE country='$country' ORDER BY city ASC");
while ($r = mysql_fetch_assoc($q)){
echo "|".$r['city'];
}

?>

This is assuming you have a database of cities with maybe three fields - id, city, country.

I hope that helps.

#10
2008-05-02 Simon says :

I want a script with two chained selects, the first one is for a main category, all the categories are extracted from a database.
The second select contains subcategories which are also selected from a database. Is this remotely possible?

#11
2008-05-02 BonRouge says :

Simon,
Yeah. Here's an example of something like that. You'll need this text file too. That's the php file referred to in the source of the demo. The example I've just given you a link to is not drawing things from a database, but hopefully one of my replies above will help with that.

Good luck.

#12
2008-05-07 Chris says :

I have this script up and running, but I need 2 or more dependent selects, (not just 1). I'm running into a lot of trouble tyring to reuse the XHR object in IE for the 2nd and 3rd, etc. dependent select fields. I've checked the solutions on http://keelypavan.blogspot.com/2006/03/reusing-xmlhttprequest-object-in-ie.html and other pages with no luck. Any thoughts on what the problem might be ?

#13
2008-06-30 Sam says :

Hi,
I am not sure why not, but it works very well with Firefox, not with IE. Any idea, what I may be missing?
Sam

#14
2008-06-30 Sam says :

I opened the link with IE from item # 11 above, posted by BonRouge that also did not work. Thanks.

#15
2008-07-01 BonRouge says :

Sam,
Sorry about the very late response (maybe you'll never see this... frown).
I see what you mean about the link in #11 - that doesn't work in IE. frown (I'll try to get back to it soon and sort it out). This page works fine for me in IE though, so I'm not sure what your problem would be there.

#16
2008-07-02 Sam says :

Hi Bon,
Does the script from Item # 11 works on your PC, when you click that one. On mine, it not only did not work, but also showed duplication of the contents of the second selection everytime I made a selection from that option list. Please advice!
-Sam

#17
2008-07-07 Greg Tallent says :

Thanks, Bon. Script works fine, including the code that retrieves cites and countries from a db.

#18
2008-07-12 Marvin says :

i need the second chained box to have a value like this:
<option value="1">Town Branch</option>. how do i print this? the data is gotten from a database, a user selects a bank and then the bank's branches are called from the database

#19
2008-08-22 Anders says :

I made a little modification to get values in the selecboxes.

here is the new function go:

function go() {
if (request.readyState == 4) {
if (request.status == 200) {
var response = request.responseText;
var list=document.getElementById("city");
var cities=response.split('|');
for (i=1; i<cities.length; i++) {
var values=cities[ i ].split(';');

var x=document.createElement('option');
x.setAttribute('value', values[0]);
var y=document.createTextNode(values[1]);
x.appendChild(y);
list.appendChild(x);
}
}
}
}

I have added two new lines:

var values=cities[ i ].split(';');
x.setAttribute('value', values[0]);

Both inside the for-loop. Now the only thing you hafte to do is change the .php file to echo in this format:

|id;text|id;text

Ex:

|1;London|2;Manchester

It works fine :-)

#20
2008-08-22 Anders (again) says :

Sorry, I also alter the line:


var y=document.createTextNode(values[1]);


#21
2008-09-14 Goody says :

Hi BonRouge,

Thank you for this wonderful code.

I tried your three field chained select menu given at #11 and I am not having any luck making it work on IE6. However it's OK with FireFox.

Your help will be much appreciated.

Regards
Goody

#22
2008-10-04 kristin says :

ah, same here! Please help.


fujiwarachiaki .... at gmail.

#23
2008-10-07 Marty says :

Would it be possible to post all the code files in a zip, on here? Also, how would it work if the data for each select needs to come from a db table?

#24
2008-11-05 DM says :

Hello,

Somehow I manage to workout this code and it acctualy helps me smile
Some time it took time for that second 'citiy' combo box to load.

I wonder is it possible to implement some (ajax) animation .gif that will disappear when 'city' list is loaded ?

hope you get me smile

Best regards,
DM

#25
2008-11-19 sercan says :

hi there,

i am a newbie on AJAX.. i just copy&pasted the codes you wrote down here.. now, i just don't know where to put the window.onLoad=initCs() code.. i guess because of this issue i couldn't make the script run frown

nothing happens when i click on the countries from the dropdown menu..

#26
2008-12-29 PP says :

Do you modify more I need 2 selectionb things life contry selected come to state and state selected to comes the area. etc..

#27
2009-01-13 Josh says :

Hi Guys, I'm pretty new to all of this and just need some guidance here. I am in need of two select boxes such as this template is designed for. The first box is for the 'Make' of a vehicle, and the second, 'Model' of vehicle that auto-populates depending on first select box selection. Anyhow, if someone would be kind enough to explain to me where the groups of code shown in the tutorial are to be placed. I copy and pasted the html code into the a text widget to place the select box in the area of the website I want. I am just unsure where the javascript code is placed along with this tidbit of JS - window.onload=initCs; . If I understand this somewhat, as I believe I do, the PHP script is placed in a php file titled: csa_ajax.php .

My last question is, once I get everything in place, can I just edit the id names and change them to suit my needs?

Thanks in advance,
Josh

#28
2009-01-30 Sathesh says :

Thanks Anders and all of you..

I was exactly looking to split this sort of thing in JS with the response text in the form: ?VALUE1;DESCRIPTION i.e. <option value="VALUE1">DESCRIPTION</option> .

I used '?' since I used '|' for some other purpose.
I got a very similar function like #19 Ander's with my own parameters and stuffs.

Really useful and many thanks again...

#29
2009-04-03 Daddyroy says :

You can database without using the swith() function

Like so:

<?php
include("link.php");
if(isset($_GET['servcCategory'])){
$servcCategory=$_GET['servcCategory'];


$SRVC2SQL="SELECT COLUMN FROM TABLE WHERE ServiceCategory='$servcCategory' ORDER BY ServiceSubcategory ASC";
$SRVC2SQLResults=mysql_query($SRVC2SQL, $link) or die(mysql_error());
while ($SVC2row = mysql_fetch_array($SRVC2SQLResults)){
$SVCSUB = $SVC2row['ServiceSubcategory'];

echo "obj.options[obj.options.length] = new Option('$SVCSUB','$SVCSUB');\n";
}

}
?>

#30
2009-06-16 fsd says :

hi i want two chained select box 1 with options to select telephone set and in second select box quantity and when we select quantity ten there,price should be appeared next to quantity select box...........can any1 help ??????????????

#31
2009-07-24 Andy says :

Bon,
Great script and have it working fine as able to fill both select boxes from my database. One query: If a particular value in the second select box has already been selected by a user (and stored on my DB) is it possible to have the javascript add SELECTED to that particular option next time they visit the page?
Thanks

#32
2009-07-25 Andy says :

Also I forgot to add- is it possible to have the menu more than 2 levels deep?
Andy

#33
2009-08-23 faiz says :

Hai Bon,
thank for the code but i have a little big problem with it.
how i want to use two chain select in same page?i having a hard time solving it tq.

#34
2009-10-08 pete says :

Not sure why but I get </BODY></HTML> on the last option.

#35
2009-11-17 windjared says :

ok, for those of you who wants to have more than 2 selected boxes, for example, i'm having 3 selected boxes, the second is depended on the first one, and the third one is depended on the second one, you need to have multiple functions:

function fillSelect(itm)
{
var url = "http://develop/web/Inventory_AJAX/inventory_ajax.php?item=" + escape(itm);
//using ajax here
request.open("GET", url, true);
request.onreadystatechange = function()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
var response = request.responseText;
var list=document.getElementById("idmake");
var makes=response.split('|');
for (i=0; i<makes.length; i++)
{
var x=document.createElement('option');
var y=document.createTextNode(makes[i ]);
x.appendChild(y);
//Damn Microsoft
//**important, the following line cost
//me freaking 3 days of researching, you have to set //the value of each 'option', otherwise, the stupid //IE won't read it
x.setAttribute("value",makes[i ]);
list.appendChild(x);
}
}
}
}
request.send(null);
}

function fillSelect2(itm, mk)
{
var url = "http://develop/web/Inventory_AJAX/inventory_ajax2.php?item=" + escape(itm) + "&make=" + escape(mk);
request.open("GET", url, true);
request.onreadystatechange = function()
{
if (request.readyState == 4)
{
if (request.status == 200)
{
var response = request.responseText;
var list=document.getElementById("idmodel");
var models=response.split('|');
for (i=0; i<models.length; i++)
{
var x=document.createElement('option');
var y=document.createTextNode(models[i ]);
x.appendChild(y);
list.appendChild(x);
}
}
}
}
request.send(null);
}

function initCs()
{
var type=document.getElementById('idtype');
type.onchange=function()
{
if(this.value!="")
{
var list=document.getElementById("idmake");
while (list.childNodes[0])
{
list.removeChild(list.childNodes[0])
}
fillSelect(this.value);
}

else
{
document.getElementById('idmake').options.length = 0;
document.getElementById('idmodel').options.length = 0;
}
}

var make=document.getElementById('idmake');
make.onchange=function()
{
if(this.value!="")
{
var list=document.getElementById("idmodel");
while (list.childNodes[0])
{
list.removeChild(list.childNodes[0])
}
fillSelect2(type.value, this.value);
}

else
{
document.getElementById('idmodel').options.length = 0;
}
}
}

window.onload=initCs;

#36
2009-11-17 windjared says :

sorry, the important line should be

x.setAttribute("value",makes[i ]);

you have my apology

#37
2009-11-17 windjared says :

ok, this website is not taking the open and close bracket sign '[' and ']'

im just gonna write it in words
x.setAttribute("value",makes *open bracket sign here* 'i' without single quote *and then close bracket*);

Sorry for the spamming.

#38
2010-01-15 GFX says :

@windjared Thank you for posting that solution to work around the IE nightmare!

For those who need a little help on where to place this line, refer to the original code:

for (i=1; i<cities.length; i++) {
var x=document.createElement('option');
var y=document.createTextNode(citiesBRACKETiBRACKET);

--> ** x.setAttribute("value",citiesBRACKETiBRACKET)

x.appendChild(y);
list.appendChild(x);
}

Obviously you'll replace BRACKET with the appropriate open or close bracket character.

#39
2010-01-22 Tomas says :

I use this great script in my site. I'm taking data to select box from mysql database. The problem is if i use data for the select box with international characters (my site is fro lithuanian users). If i use characters like or &#268; in words, the 2nd chaned select box returns empty field. Any ideas for this? THX.

#40
2010-01-22 Alex says :

Hi guys,
I think we all need a little bit of clearness... all these modifying the scripts... could someone (BonRouge, i.e.) do it, please? I'm losing my head! ;-)

Thanx!

#41
2010-03-29 Jaspreet says :

Please could someone guide on how to do this step by step......Please i dont know where to place the window.onload=initCs . Please help me out

#42
2010-08-19 maswewe says :

Please could someone guide on how to do this step by step......Please i dont know where to place the window.onload=initCs . Please help me out

put em at the top of the javascript code.
before the..

'var request = false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)'..

and it would works..

my band

#43
2010-11-11 jy says :

what if you have multiples of this chained select.
the id will be the same,but then you will have change in country[0] corresponding to city[0], change in country[1] corresponding to city[1] and so on...
How to implement this script in array form?

#44
2010-11-12 BonRouge says :

jy,
Here's a page with many of these: chain select js boxes. The difference is that this example uses arrays rather than AJAX and a database. I hope you can use that or see how to adapt it.

#45
2010-11-12 jy says :

Can you post the code, i am not sure how to modify the response page,

#46
2010-11-29 jy says :

I was able to solve this by first creating a loop in php by creating multiple drop down list , and giving them different ids, then use javascript to get the id from the dropdown list.

#47
2011-03-22 not spamming-kevin says :

dunno if people still checking this but I have gotten this script to work perfectly... The only thing I am having trouble with is trying to load the page with the 3 drop downs filled in with what has been stored per user.

I can get the first to populate with the 'selected' element but the send list loads all list items and no selected.

I have the 2nd and 3rd values in both my index page and my chain.php page but I can't figure out where to put them...

#48
2011-04-19 jj says :

hi any body write how to save this form. That means if i add submit button does it work. how this submit button save data to mysql database table

#49
2011-04-20 Paul says :

Hi,

Is anyone up for making the following three wheel spinner chained dependency from data in a MYSQL DB?

Can use data country, city, football team.

http://cubiq.org/spinning-wheel-on-webkit-for-iphone-ipod-touch/comment-page-4#comment-23606

If so let me know and we can talk about effort required and fee etc.

Thanks

#50
2011-05-03 jj says :

hi any body help me to save this form. That means if i add submit button does it work. how this submit button save data to mysql database table.

#51
2011-08-26 Casper says :

Using onchange="javascript_function();" would be so much better.

#52
2011-08-27 BonRouge says :

Caspar,
Why would that be?

#53
2012-01-16 rajni says :

im new to this ajax: and i have taken the above code
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script language="javascript" type="text/javascript">
var request = false;
/*@cc_on @*/
/*@if (@_jscript_version >= 5)
try {
request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
request = false;
}
}
@end @*/
if (!request && typeof XMLHttpRequest != 'undefined') {
request = new XMLHttpRequest();
}

function fillSelect(country) {
var url = "csa_ajax.php?district=" + escape(country);
//alert(url);
request.open("GET", url, true);
request.onreadystatechange = go;
request.send(null);
}

function go() {
if (request.readyState == 4) {
if (request.status == 200) {
var response = request.responseText;
var list=document.getElementById("taluka");
//alert(list);
var cities=response.split('|');
for (i=1; i<cities.length; i++) {
var x=document.createElement('option');
var y=document.createTextNode(cities);
x.appendChild(y);
list.appendChild(x);
}
}
}
}

function initCs() {
var country=document.getElementById('district');
//alert(country);
country.onchange=function() {
if(this.value!="") {
var list=document.getElementById("taluka");
//alert(list);
while (list.childNodes[0]) {
list.removeChild(list.childNodes[0])
}
fillSelect(this.value);
}
}
fillSelect(country.value);
}

</script>

if i remove the above <DOCtype >then only it is workin

#54
2012-06-27 Bassie says :

Hi everybody,

Great script, however i am having trouble connecting it to a database. The connection works fine, but i want to retrieve both an ID from the database that i want to use as VALUE in the option list and offcourse a displayed text from the database, for instance a city. I mean: <option value="1">Amsterdam</option>, both coming from a database

#55
2013-03-07 Arpit says :

It shows 2times the contents in the box

Comment form

Please type the word 'Valencia' here:

BB code available :

  • [b]...[/b] : bold
  • [it]...[/it] : italic
  • [q]...[/q] : quote
  • [c]...[/c] : code
  • [url=...]...[/url] : url