I need to display three select menus for selecting State, District and Area. In which the Second select menu should be populated dynamically based on the first and third based on the second.
For this, I found one at Javascriptsource.com (archived) and replaced a little to get the following,
<script>
var districts = new Array();
districts['Tamilnadu'] = new Array('Chennai','Coimbatore','Vellore');
districts['Andhra Pradesh'] = new Array('Hyderabad','Andra 2','Andra 3');
var cities = new Array();
areas['Tamilnadu'] = new Array();
areas['Tamilnadu']['Chennai'] = new Array('Kolathur','Perambur');
areas['Tamilnadu']['Coimbatore'] = new Array('Combatore 1','Coimbatore 2');
areas['Tamilnadu']['Vellore'] = new Array('Vellore 1','Vellore 2');
areas['Andhra Pradesh'] = new Array();
areas['Andhra Pradesh']['Hyderabad'] = new Array('Hyde 1','Hyde 2');
areas['Andhra Pradesh']['Andra 2'] = new Array('Andra2 1','Andra2 2');
areas['Andhra Pradesh']['Andra 3'] = new Array('Andra3 1','Andra3 2');
function setDistrict() {
stateSelect = document.getElementById('state');
districtList = districts[stateSelect.value];
changeSelect('district', districtList, districtList);
setArea();
}
function setArea() {
stateSelect = document.getElementById('state');
districtSelect = document.getElementById('district');
areaList = areas[stateSelect.value][districtSelect.value];
changeSelect('area', areaList, areaList);
}
function changeSelect(fieldID, newOptions, newValues) {
selectField = document.getElementById(fieldID);
selectField.options.length = 0;
for (i=0; i<newOptions.length; i++) {
selectField.options[selectField.length] = new Option(newOptions[i], newValues[i]);
}
}
// The below codes do what?
function addLoadEvent(func) {
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = func;
} else {
window.onload = function() {
if (oldonload) {
oldonload();
}
func();
}
}
}
addLoadEvent(function() {
setDistrict();
});
</script>
And it works fine except the third select menu does not get populated when the second select menu's value change.
What is wrong there and i also like to know whether this works on all major browsers or not?
Is there any better solution for this? and can anyone explain what the last block of code(after the comment line) actually do?
Thanks in advance.
[ I did searching for the answer both here in stackoverflow and in other places. But nothing seems to be helpful for this need of using just javascript. ]
[UPDATE] It is working now. But will it work on all browsers and can anyone explain me what the code after the comment line do?
There are several issues there.
It looks like the main issue is that you're not declaring areas
anywhere; you're declaring cities
instead.
The code is also suffering from The Horror of Implicit Globals by not declaring its variables.
Even when declaring its variables, the code is making them globals. There's no need for that here, it's better to wrap the whole thing in a scoping function to avoid conflicts in the (very crowded) global namespace. It looks like you must be using changeSelect
in an HTML onXyz
attribute somewhere, so we have to do something to make it global (the better answer would be not to use HTML onXyz
attributes, but instead use attachEvent
(IE8 and earlier) or addEventListener
(all others) on the select
elements in code (I haven't tried to do that below, I just made changeSelect
global).
The code where you've asked "The below codes [sic] do what?" is trying to wait to call setDistrict
until after the select
elements defined by the HTML exist. But that code is very out of date. In the mid 1990s, if you wanted to run a function when the page was done loading, you assigned it to window.onload
or put it in the opening <body>
tag as <body onload="functionName();">
. There could only be one of these, if you did it again, it removed the first. So that code is trying to see if there's already one there, and if there is, replace it with the new one but also call it.
Fortunately, in the late 90's Microsoft introduced attachEvent
in IE 5.5 (5.0?) and soon thereafter we had DOM2 Events which gave us addEventListener
in all other browsers, both of which let us do the same thing without removing any previous handler.
But there's no need to wait for the window
load
event here, and it's a bad idea because it doesn't fire until after everything loads, including all of your images. Instead, we just put the script
element with this code at the very end of your HTML, just before the closing </body>
tag, and call setDistrict()
directly:
// Just make sure this script is referenced from a `script` element
// at the **end** of the HTML, just before the closing `</body>` tag
setDistrict();
The elements will exist at that point. No reason to wait any longer than that (and window.onload
is a lot later).
Neither districts
nor areas
(or some of the area
sub-elements) should be arrays. They're not being used as arrays at all, just as objects. All of that initialization of districts
and areas
can be much simpler.
Do putting all of that together, with some proper formatting:
// Scoping function prevents the `vars` inside from being globals
(function() {
// Create our districts and areas
var districts = {
"Tamilnadu": ["Chennai", "Coimbatore", "Vellore"],
"Andhra Pradesh": ["Hyderabad", "Andra 2", "Andra 3"]
};
var areas = {
"Tamilnadu": {
"Chennai": ["Kolathur", "Perambur"],
"Coimbatore": ["Combatore 1", "Coimbatore 2"],
"Vellore": ["Vellore 1", "Vellore 2"]
},
"Andhra Pradesh": {
"Hyderabad": ["Hyde 1", "Hyde 2"],
"Andra 2": ["Andra2 1", "Andra2 2"],
"Andra 3": ["Andra3 1", "Andra3 2"]
}
};
function setDistrict() {
// Note the use of `var` to make these variables local to the function
var stateSelect = document.getElementById('state');
var districtList = districts[stateSelect.value];
changeSelect('district', districtList, districtList);
setArea();
}
function setArea() {
// Note the use of `var` to make these variables local to the function
var stateSelect = document.getElementById('state');
var districtSelect = document.getElementById('district');
var areaList = areas[stateSelect.value][districtSelect.value];
changeSelect('area', areaList, areaList);
}
// Make `changeSelect` available globally
window.changeSelect = changeSelect;
function changeSelect(fieldID, newOptions, newValues) {
// Note the use of `var` to make these variables local to the function
var i;
var selectField = document.getElementById(fieldID);
selectField.options.length = 0;
for (i = 0; i < newOptions.length; i++) {
selectField.options[selectField.length] = new Option(newOptions[i], newValues[i]);
}
}
// Make sure this script is at the *end* of the HTML, just above the
// closing </body> tag
setDistrict();
})();
Side note: When talking about programming code, the word "code" is a "mass noun" like "water". It's never plural. So it's always "this code" not "these codes."