Creating client-side dynamic dependent list boxes
| Dreamweaver UltraDev is no longer supported, and the Dreamweaver UltraDev support center will no longer be actively updated. The functionality available in Dreamweaver UltraDev is available in Dreamweaver, beginning with Dreamweaver MX. Accordingly, we are moving pertinent content to the Dreamweaver support center. Please refer to the Dreamweaver version of this technote: Creating client-side dynamic dependent list boxes in ASP (TechNote 19117). |
Introduction
Client-side dynamic dependent list boxes allow a "child" list box to refresh when a selection is made in a "parent" list box, without having to return to the server. Most dynamic dependent list box models return to the server to requery the dependent list box's recordset. The model described in this TechNote passes dependent list box data to the browser in an array. It uses JavaScript to extract the appropriate values from the array and refresh the "child" list box in the client's browser.
The advantage to this approach is immediate page response; the user does not have to wait for the new page to be delivered from the remote server. The disadvantage is all the data for the dynamic dependent list box is sent to the client as text, thus increasing the size of the requested page. An evaluation must be made whether the increased page size warrants saving return trips to the server. If the amount of data required for the dynamic dependent list box is not significant, page size remains relatively small.
Multiple dynamic dependent list boxes can be added to a page. The extra steps to do this are documented at the end of this TechNote.
The model described here has a "parent" list box created normally in UltraDev. It can be either dynamic or static. The model also has a "child" dynamic dependent list box created in UltraDev as a normal List/Menu object. The "child" dynamic dependent list box is made dynamic on the client side with the addition of the code presented here.
Building the page
- Add the "parent" list box to the page. Add either hard coded or dynamic Item Labels and Values to it.
- Add the "child" list box to the page. Do not add any Item Labels or Values to it.
- Create a recordset for the child list box, which must include fields for its Item Labels, Values, and the relationship to the parent list box as explained in Relating the list boxes.
- Copy the appropriate VBScript or JavaScript code and paste into the page's HTML code window just above the closing head tag.
- Change the object names in the pasted code as explained in Object names.
- Add the Call JavaScript behavior(s) as explained in Final changes.
- Apply the code to view dynamic listboxes in Netscape 4 as explained in Netscape 4 Modification.
- If errors occur when viewing the page, or the dependent list box does not function correctly, check Troubleshooting.
- To add more than one dynamic dependent list box to a page, follow the instructions in Multiple dynamic dependent list boxes on one page.
Relating the list boxes
When defining the relationship between the parent and child list boxes, two rules apply.
- The Value of the parent list box is used to filter the data used to populate the child list box.
- A field in the child list box's recordset must correspond to the Value in the parent list box (the "relation").
The following example shows a parent list box populated with two Item Labels;Colors and Shapes;with their corresponding values. The child list box is populated in the client browser from a recordset with three fields. The Relation field identifies the relationship with the Value of the parent list box. The Item Label field will be displayed in the child list box. The Value field is returned to the server corresponding to the item label selected by the user.
| Parent list box | Child list box | |||
| Item Label | Value | Relation | Item Label | Value |
| Colors | ColorCode | ColorCode | Blue | 1 |
| ColorCode | Red | 2 | ||
| ColorCode | Green | 3 | ||
| ColorCode | Yellow | 4 | ||
| Shapes | ShapeCode | ShapeCode | Square | A |
| ShapeCode | Circle | B | ||
| ShapeCode | Triangle | C |
| Parent list box | Child list box |
| [/topic/body/section/form/table/tgroup/tbody/row/entry/select {""}) Colors Shapes (select] | [/topic/body/section/form/table/tgroup/tbody/row/entry/select {""}) Blue Red Green Yellow (select] |
BACK TO Building the Page
Object names
The code provided in this TechNote uses the following object names which must be renamed to the corresponding object names from your page.
| selList1 | Name of the parent list box, defined in UltraDev. |
| form1 | Form name containing the selList1 object. |
| selList2 | Name of the child list box populated by this code on the client side after making a selection in selList1. |
| form2 | Form name containing the selList2 object (usually the same form selList1 uses). |
| rsList2 | Recordset used to populate the child list box, selList2, from an array on the client side. |
| "Relation" | Field name from rsList2 used to define the relationship with selList1. |
| "Label" | Field name from rsList2 used to fill the Item Label column of selList2. |
| "Value" | Field name from rsList2 used to fill the Value column of selList2. |
Note: By naming your objects with the above names, only "Relation", "Label", and "Value" (and possibly form2) need to be changed in the provided code.
BACK TO Building the Page
Client-side dynamic dependent list box code - VBScript
Client-side dynamic dependent list box code
This code creates the array for the client side from the recordset rsList2. It also includes the functions called when the first list box is changed. setDynaList() controls the functions. clearDynaList() clears existing elements from selList2. populateDynaList() adds elements to selList2 based on the value selected in selList1.
The client-side dynamic dependent list box code is available for VBScript (this code) or JavaScript server-side scripting languages in ASP pages.
Code insertion location
Insert the code provided in the head section of the page, right above the closing head tag. Make sure the first two lines and last two lines are not contained within any other open and closed script tags, or a nesting error will occur.
Replace the eight object names in red with your object names. Make sure to leave the quotation marks in the code.
<!-- Dynamic Dependent List box Code for *** VBScript *** Server Model //--><script ><!-- var arrDynaList = new Array(); var arrDL1 = new Array(); arrDL1[1] = "selList1"; // Name of parent list box arrDL1[2] = "form1"; // Name of form containing parent list box arrDL1[3] = "selList2"; // Name of child list box arrDL1[4] = "form2"; // Name of form containing child list box arrDL1[5] = arrDynaList;<% Dim txtDynaListRelation, txtDynaListLabel, txtDynaListValue, oDynaListRS txtDynaListRelation = "Relation" ' Name of recordset field relating to parent txtDynaListLabel = "Label" ' Name of recordset field for child Item Label txtDynaListValue = "Value" ' Name of recordset field for child Value Set oDynaListRS = rsList2 ' Name of child list box recordset Dim varDynaList varDynaList = -1 Dim varMaxWidth varMaxWidth = "1" Dim varCheckGroup varCheckGroup = oDynaListRS.Fields.Item(txtDynaListRelation).Value Dim varCheckLength varCheckLength = 0 Dim varMaxLength varMaxLength = 0 While (NOT oDynaListRS.EOF) If (varCheckGroup <> oDynaListRS.Fields.Item(txtDynaListRelation).Value) Then If (varCheckLength > varMaxLength) Then varMaxLength = varCheckLength End If varCheckLength = 0 End If %> arrDynaList[<%=(varDynaList+1)%>] = "<%=(oDynaListRS.Fields.Item(txtDynaListRelation).Value)%>" arrDynaList[<%=(varDynaList+2)%>] = "<%=(oDynaListRS.Fields.Item(txtDynaListLabel).Value)%>" arrDynaList[<%=(varDynaList+3)%>] = "<%=(oDynaListRS.Fields.Item(txtDynaListValue).Value)%>"<% If (len(oDynaListRS.Fields.Item(txtDynaListLabel).Value) > len(varMaxWidth)) Then varMaxWidth = oDynaListRS.Fields.Item(txtDynaListLabel).Value End If varCheckLength = varCheckLength + 1 varDynaList = varDynaList + 3 oDynaListRS.MoveNext() Wend If (varCheckLength > varMaxLength) Then varMaxLength = varCheckLength End If %> //--></script><!-- End of object/array definitions, beginning of generic functions --><script ><!-- function setDynaList(arrDL){ var oList1 = document.forms[arrDL[2]].elements[arrDL[1]]; var oList2 = document.forms[arrDL[4]].elements[arrDL[3]]; var arrList = arrDL[5]; clearDynaList(oList2); if (oList1.selectedIndex == -1){ oList1.selectedIndex = 0; } populateDynaList(oList2, oList1[oList1.selectedIndex].value, arrList); return true; } function clearDynaList(oList){ for (var i = oList.options.length; i >= 0; i--){ oList.options[i] = null; } oList.selectedIndex = -1; } function populateDynaList(oList, nIndex, aArray){ for (var i = 0; i < aArray.length; i= i + 3){ if (aArray[i] == nIndex){ oList.options[oList.options.length] = new Option(aArray[i + 1], aArray[i + 2]); } } if (oList.options.length == 0){ oList.options[oList.options.length] = new Option("[none available]",0); } oList.selectedIndex = 0; } //--></script>
BACK TO Building the Page
Client-side dynamic dependent list box code - JavaScript
Client-side dynamic dependent list box code
This code creates the array for the client side from the recordset rsList2. It also includes the functions called when the first list box is changed. setDynaList() controls the functions. clearDynaList() clears existing elements from selList2. populateDynaList() adds elements to selList2 based on the value selected in selList1.
The client-side dynamic dependent list box code is available forVBScript or JavaScript (this code) server-side scripting languages in ASP pages.
Code insertion location
Insert the code provided in the head section of the page, right above the closing head tag. Make sure the first two lines and last two lines are not contained within any other open and closed script tags, or a nesting error will occur.
Replace the eight object names in red with your object names. Make sure to leave the quotation marks in the code.
<!-- Dynamic Dependent List box Code for *** JavaScript *** Server Model //--><script ><!-- var arrDynaList = new Array(); var arrDL1 = new Array(); arrDL1[1] = "selList1"; // Name of parent list box arrDL1[2] = "form1"; // Name of form containing parent list box arrDL1[3] = "selList2"; // Name of child list box arrDL1[4] = "form2"; // Name of form containing child list box arrDL1[5] = arrDynaList;<% var txtDynaListRelation, txtDynaListLabel, txtDynaListValue, oDynaListRS; txtDynaListRelation = "Relation" // Name of recordset field relating to parent txtDynaListLabel = "Label" // Name of recordset field for child Item Label txtDynaListValue = "Value" // Name of recordset field for child Value oDynaListRS = rsList2 // Name of child list box recordset var varDynaList = -1; var varMaxWidth = "1"; var varCheckGroup = oDynaListRS.Fields.Item(txtDynaListRelation).Value; var varCheckLength = 0; var varMaxLength = 0; while (!oDynaListRS.EOF){ if (varCheckGroup != oDynaListRS.Fields.Item(txtDynaListRelation).Value) { varMaxLength = Math.max(varCheckLength, varMaxLength) varCheckLength = 0; } %> arrDynaList[<%=(varDynaList+1)%>] = "<%=(oDynaListRS.Fields.Item(txtDynaListRelation).Value)%>"; arrDynaList[<%=(varDynaList+2)%>] = "<%=(oDynaListRS.Fields.Item(txtDynaListLabel).Value)%>"; arrDynaList[<%=(varDynaList+3)%>] = "<%=(oDynaListRS.Fields.Item(txtDynaListValue).Value)%>";<% if (oDynaListRS.Fields.Item(txtDynaListLabel).Value.length > varMaxWidth.length) { varMaxWidth = oDynaListRS.Fields.Item(txtDynaListLabel).Value; } varCheckLength = varCheckLength + 1; varDynaList = varDynaList + 3; oDynaListRS.MoveNext(); } varMaxLength = Math.max(varCheckLength, varMaxLength) %> //--></script><!-- End of object/array definitions, beginning of generic functions --><script ><!-- function setDynaList(arrDL){ var oList1 = document.forms[arrDL[2]].elements[arrDL[1]] var oList2 = document.forms[arrDL[4]].elements[arrDL[3]] var arrList = arrDL[5] clearDynaList(oList2); if (oList1.selectedIndex == -1){ oList1.selectedIndex = 0; } populateDynaList(oList2, oList1[oList1.selectedIndex].value, arrList); return true; } function clearDynaList(oList){ for (var i = oList.options.length; i >= 0; i--){ oList.options[i] = null; } oList.selectedIndex = -1; } function populateDynaList(oList, nIndex, aArray){ for (var i = 0; i < aArray.length; i= i + 3){ if (aArray[i] == nIndex){ oList.options[oList.options.length] = new Option(aArray[i + 1], aArray[i + 2]); } } if (oList.options.length == 0){ oList.options[oList.options.length] = new Option("[none available]",0); } oList.selectedIndex = 0; } //--></script>
BACK TO Building the Page
Final changes
After inserting the code into your page and renaming the objects to your object names, only one or two more changes are needed.
- Select the selList1 list box object. From the Behaviors panel, add the Call JavaScript behavior. Enter
setDynaList(arrDL1)(capitalization counts!) in the Call JavaScript dialog box. Make sure the action is added to the onChange event for the list box. This causes the child list box contents to update when a change is made in the parent list box. - Select the body tag in the lower left border of the page. From the Behavior inspector, add the Call JavaScript behavior. Enter
setDynaList(arrDL1)(capitalization counts!) in the Call JavaScript dialog box. Make sure the action is added to the onLoad event. This step is optional. It will initialize selList2 when the page loads on the basis of the default value for selList1.
BACK TO Building the Page
Netscape 4 Modification
An extra modification is needed for Netscape 4 browsers to properly view the dynamic listbox. If the dynamically populated listbox does not have any initial values, Netscape 4 will not resize the listbox to accommodate the dynamically populated contents. The listbox is essentially unusable. To remedy the situation, this modification will initially populate the listbox with the widest item label and the largest number of item labels from your child listbox recordset groups. As long as you call thesetDynaList function from the onLoad event, these initial values will not be displayed.
Note: The "largest number of item labels" means the number of items in the largest Relation group. In the above color/shape example, this value is 4, because there are four ColorCodes. To insure the correct maximum is calculated, the recordset must be sorted by Relation (you can add secondary sorts as well, for example by Label).
In the source code, the HTML for the child listbox will appear as follows (with your name if you used a different name):
<select name="selList2"></select>
Replace the code for the child listbox with the following if you are using the VBScript server model:
<select name="selList2"><% Dim varLoopCounter For varLoopCounter = 1 TO varMaxLength %><option value = "<%=varMaxWidth%>"><%=varMaxWidth%></option><% Next %></select>
Replace the code for the child listbox with the following if you are using the JavaScript server model:
<select name="selList2"><% for (varLoopCounter = 1; varLoopCounter <= varMaxLength; varLoopCounter++){ %><option value = "<%=varMaxWidth%>"><%=varMaxWidth%></option><% } %></select>
BACK TO Building the Page
Troubleshooting
- Verify the object names have been changed correctly as explained in Object names. This is the most common problem encountered.
- Verify the "relation" field in the child list box recordset corresponds to the parent list box's Value as explained in Relating the list boxes.
- Verify the correct code has been inserted for your server-side scripting language, VBScript or JavaScript.
- Try rebuilding the page from scratch, or building a simple test page.
BACK TO Building the Page
Multiple dynamic dependent list boxes on one page
The provided code can easily be enhanced to accommodate more than one dynamic dependent list box on a page. The functions are generic, so no modifications are needed for the functions section of code. Follow these steps to add another dynamic dependent list box.
- Copy the top half of the code down to the following line:
<!-- End of object/array definitions, beginning of generic functions --> - Paste the code segment into a text editor to perform the following modifications.
- In the same manner as explained above for the first set of list boxes, rename the objects in the code to correspond to your object names.
- Rename the following objects. As long as they do not conflict with other object names in the page, and changes are made consistently to all references in the code, the new names are not so important. Use a Find/Replace function to ensure all instances are changed correctly.
Original Name New Name arrDynaList arrDynaList2 arrDL1 arrDL2 txtDynaListRelation txtDynaListRelation2 txtDynaListLabel txtDynaListLabel2 txtDynaListValue txtDynaListValue2 oDynaListRS oDynaListRS2 varDynaList varDynaList2 Note: For a third pair of dynamic dependent list boxes, use names such as "arrDynaList3", and so forth and so on.
- Add new Call JavaScript behaviors to the new parent list box's onChange event and to the body's onLoad event. This time, use the new array name as the parameter in the function call. For example,
setDynaList(arrDL2).You may also want to add
setDynaList(arrDL2)to the onChange event of another list box, if you now have a grandparent/parent/child relationship. - Check the source code of any multiple onLoad and onChange JavaScript calls. Starting with the top level list box and working down, make sure the functions execute in the proper order.
<select onChange="setDynaList(arrDL1);setDynaList(arrDL2)" name="selList1">
This content requires Flash
To view this content, JavaScript must be enabled, and you need the latest version of the Adobe Flash Player.
Download the free Flash Player now!
