I need to modify a dependent drop-down

We have an app on our site with a search form that has two <select> items, with the contents of the second one being dependent on what’s chosen in the first.

The original app had a problem with the way the database was designed so that all searches were done as wildcard text searches. I’ve since normalized that database, and would like to change this form to pass numerical values instead of text ones.

For the first <select> that’s easy, because it’s generated from a db query. The second one however is done with Javascript, and I’m pretty horrible with JS. The current JS for the second <select> goes like this:

function populateSubdisciplines() {
			var o = document.getElementById("discipline");
			d = document.getElementById('subdiscipline');
			if(!d){return;}			
			var mitems=new Array();
			mitems['114']=['[all]', 'Category One', 'Category Two', 'Category Three', 'Category Four'];
			mitems['115']=['[all]', 'Category One', 'Category Three', 'Category Four', 'Category Seven'];
			// Clear any entries in the subdisciples list box
			d.options.length=0;

			if (o.selectedIndex === -1) { return; }
			var cur = mitems[o.options[o.selectedIndex].value];
			if(!cur){return;}
			d.options.length=cur.length;
			for(var i=0;i<cur.length;i++) {
				d.options[i].text = cur[i];
				d.options[i].value = cur[i];
			}
		}

This renders the following:

<select name="second">
<option value="Category One">Category One</option>
<option value="Category Two">Category Two</option>
<option value="Category Three">Category Three</option>
<option value="Category Four">Category Four</option>
</select>

What I’m trying to get is this:

<select name="second">
<option value="23">Category One</option>
<option value="71">Category Two</option>
<option value="98">Category Three</option>
<option value="125">Category Four</option>
</select>

So I need to figure out how to modify the JS above to do that. Ideally, I’d make my code build the JS from the database so that editing the JS wouldn’t be needed when new options are added, but maybe I can figure that out once I figure out how to pass the IDs with the names.

This is the line that you need to change:

d.options[i].value = cur[i];

It seems that o.options[o.selectedIndex].value is used to select the numeric index from the mitems array, so try the following:

d.options[i].value = o.options[o.selectedIndex].value

Thanks Paul! I’ll give that a try as soon as I’m back in the office tomorrow.

Do you know if there’s any hope of retaining the selected option on the second box after the form has been submitted (the page with the form submits to itself). The old JS doesn’t.

It is possible to submit the form without reloading the page. That would allow the options to remain as they currently are. Is that what you’re wanting to achieve?

Well that would certainly work. I’m trying to retain the selected options and keywords in the form after the first search is performed, so that the user doesn’t have to pick all the options again. So far I can retain them all except for that second <select>.

Well as a second option, which may indeed be easier - why don’t you run that populateSubdisciplines function when the page loads? That would allow the second set of options to appear for you again.

Hmm, alright. It seems like I probably need to change these lines too, no?

mitems['114']=['[all]', 'Category One', 'Category Two', 'Category Three', 'Category Four'];
mitems['115']=['[all]', 'Category One', 'Category Three', 'Category Four', 'Category Seven'];

Since they look like they’re what builds the new options.

Now you have me confused. What makes you think that those lines need to be changed? I thought that they were indicative of what each subcategory may be, depending on the value of the main category is.

Well, the 114 at the beginning of that line is the parent category ID from the first <select>, and I want the second dropdown to have the child ID as the value= and the child name as the text for the option, like in the example <select> I pasted up above.

I’m thinking I should have something like this:

mitems['114']=['[0, all]', '[23, Category One]', '[71, Category Two]', '[98, Category Three]', '[125, Category Four]'];

But of course the JS doesn’t work well with that.

Ahh yes - you can achieve that by using an object structure.


mitems[114] = [
    {id: '0', value: 'all'}, {id: '23', value: 'Category One'}, {id: '71', value: 'Category Two'}, {id: '98', value: 'Category Three'}, {id: '125', value: 'Category Four'}
];

So, item = mitems[114][2] would give you {id: ‘71’, value: ‘Category Two’} from which you can get the id with item.id and the value with item.value

If you want to define multiple sets of items at a time, it can be done with:


mitems = {
    '114': [
        {id: '0', value: 'all'}, {id: '23', value: 'Category One'}, {id: '71', value: 'Category Two'}, {id: '98', value: 'Category Three'}, {id: '125', value: 'Category Four'},
    ],
    '115': [
        // similar to above
    ]
};

Perfect!