A most wanted script for the
form elements so that upon selecting one option can be accordingly triggered an update to the set of options of another select list.
A
select-one menu is defined by the following tags and properties (mandatory their allocation in between a
form tag):
<select name="aName" onChange="myFunction()">
<option value="aValue for option 0">text for option 0 here</option>
<option value="aValue for option 1">text for option 1 here</option>
... ... ... ... ... ... et caetera ... ... ... ... ... ...
</select>
Please note:
- Every select tag must carry a unique name to identify it
- The onChange property is what determines the subroutine which has to run upon selection of an item
- The options define the amount of selections. Note that:
- They are always counted starting with zero
- Each of them carries an invisible value and a visible text
So what we want to achieve is, within an environment where there are at least two select menus, to completely rewrite
both the
values and the
texts of a select menu upon a selection (onChange) in the other select menu.
It is
important for you to fully understand that when you're on rewriting the texts of a select tag, you must also rewrite the
value properties of each option and not just their texts. In fact the texts reveal, through a string which is either appealing or explicative to humans, what the option is about, but it is its hidden value which normally carries a string of programming data that would be meaningless to humans but that none the less are mission critical for your application. A typical example is the option which carries in the
text a string describing a website title (such as:
my cool website...) and that carries in the
value an often complex
Url [
Uniform Resource Locator, a
web address that is] which might be weird enough to justify the necessity to hide it (such as:
http://www.supersonicrafts/specials/unmanned/stealth/comments/02730.987.00564.denver.09.asp).
I really do not care if you need or not to rewrite both of them, both
values and texts: I want you to do it anyway if we are to spread
good programming practice...
In this case we are building a method (we say in this case this is, more appropriately, just an object, since it does not perform or inflict any modification to the linked object, but simply describe that it has two trailing properties named value and text); this method (better: object) is thus called
selectObjectSet and will accomplish a pretty simple thing: it will be the storehouse for the two properties that we called value and text (we could have called them johnnie and walker as well...) to make more intuitive what they will be meant for and to store what...
We can now get avail of another keyword in javascript, the keyword
new and initialize through it as many new
selectObjectSet objects as we prefer.
Thus here is the trick: we build an array whose each entry is a... new selectObjectSet object...:
var storehouse=new Array()
storehouse[0]=new selectObjectSet()
storehouse[1]=new selectObjectSet()
storehouse[2]=new selectObjectSet()
storehouse[3]=new selectObjectSet()
//... you could go on. Just start with index ZERO
In other words, you have to initialize one of those strings (if just one, just one. But do
be sure, absolutely sure, that you start with the first index set as zero, and whatever subsequent object counting up from there) for each select object that you have to redraw. Suppose you have select1 and select2: both select1 and select2 have their full set of texts and values. But since you want to rewrite one of them, you have to gather somewhere the texts and values of the
new select which is to be drawn: thus you get avail of a
storehouse entry.
So let's imagine the
simplest possible case: you have only one storehouse entry since you need to update only one select box (although I must say that the simplest case is the case where you are forced to use ...
2 storehouse entries, since once you have redrawn the list of options, what if you want to
reset them to their original...? They got lost until you have handwritten a copy in another storehouse entry. Got it? Think of it...).
Once you have initialized it
var storehouse=new Array()
storehouse[0]=new selectObjectSet()
you must remember that every
selectObjectSet() has two properties as we defined it:
- text
- value
This means that every
new selectObjectSet object will have those properties, so even this
single storehouse[0] entry will have it:
storehouse[0].text
storehouse[0].value
Take courage, you're required a last effort: we initialized each property (both text and value, that is) of every selectObjectSet object like a...
new Array, remember?
So they are arrays: thus to store in it both texts and values of the new select menu which is going to be built you just have to index the array and assigning the values:
var storehouse=new Array()
storehouse[0]=new selectObjectSet()
storehouse[0].text[0]="New FIRST TEXT"
storehouse[0].text[1]="New SECOND TEXT"
storehouse[0].text[2]="New THIRD TEXT"
storehouse[0].value[0]="New FIRST VALUE"
storehouse[0].value[1]="New SECOND VALUE"
storehouse[0].value[2]="New THIRD VALUE"
I believe this is convincing, although you are right: it requires your participation: you have to write all the texts. This is not a shortfall of the method: it is simply impossible for a computer to design from scratch a new select menu without knowing with what texts and values it has to populate it. Once again, convincing: isn't it?
Now you have to build the two selects: say the first is named select1 and is the one that triggers the update in the second select named select2. Thus in the options of the select1 you have to set the values to the storehouse[index] it must grab upon selecting that option:
<select name="select1" onChange="updateMenu()">
<option value="storehouse[0]">Reset target menu</option>
<option value="storehouse[1]">Change target menu</option>
</select>
<select name="select2" onChange="foofoo(this.options[this.selectedIndex])">
<option value="old value option 0">old text option 0</option>
<option value="old value option 1">old text option 1</option>
<option value="old value option 2">old text option 2</option>
</select>
Now in the SCRIPT include for storehouse[0] a list of texts and values to reset the old values (we assume you want to do this) and in storehouse[1] the new values: Here full script prior to the basic function:
Now here is your subroutine: it is the subroutine which is invoked by the
onChange event of the select1 (that was the name we assigned to it), while the select2 (which is to undergo the changes) invokes onChange a foofoo() subroutine which is just a placeholder. In our case we want to define it just for providing you with a working example:
function foofoo(obj){
alert(obj.value)
}
That will simply trigger an alert showing the value, so you will see also values are updated in the example we provide below. Main function now!
function updateMenu(target,store){
store=eval(store)
target.options.length=store.text.length
for(var i=0;i<store.text.length;i++){
target.options[i].text=store.text[i]
target.options[i].value=store.value[i]
}
}
You invoke it from select1 passing arguments as follows:
- target argument: must be a full reference to the targeted select box, thus a path like:
document.formName.select2
in our case formName would be, obviously, select2 (do not get confused assigning select1...)
- The store argument must be exactly the following line:
this.options[this.selectedIndex].value
Thus here is the invocation from the onChange event of select1 (and please, do not forget the in between the two arguments and do not... invert them! And do not add the keyword
options after select2 name...