Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Dynamic Update of DropDown 1

Status
Not open for further replies.

phzero

Programmer
Joined
Feb 14, 2002
Messages
86
Location
ZA
Hi All,

I have 2 dropdowns, the second one's contents depend on the selection made in the first one. I can populate them but am unable to dynamically update the second based on the selection in the first. I get my variables from a SQL Server database. Thanks in advance for any replies. Here is my existing code:

<%@ language=&quot;vbscript&quot; %>
<% option explicit %>

<!--#include file=&quot;Includes/adovbs.inc&quot;-->
<!--#include file=&quot;Includes/FunctionCalls.asp&quot;-->

<HTML>
<HEAD>
<meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=iso-8859-1&quot;>
<meta http-equiv=&quot;Pragma&quot; content=&quot;no-cache&quot;>
<meta http-equiv=&quot;cache-control&quot; content=&quot;private, no-cache, must-revalidate&quot;>
<link rel=&quot;stylesheet&quot; href=&quot;styles/global.css&quot; type=&quot;text/css&quot;>

<%
dim rsMainCat
OpenConnection

set rsMainCat = CreateObject(&quot;ADODB.Recordset&quot;)
rsMainCat.Open &quot;select * from CategoryInfo, db, adOpenKeyset, adLockOptimistic

%>

</HEAD>
<BODY bgColor=White>
<form name=&quot;LogIncident&quot; method=&quot;post&quot; action=&quot;AddIncident.asp&quot;>
<table>
<tbody>
<tr><td colspan=2><h1>Please Log Your Request</h1></td></tr>
<tr><td colSpan=2><h4>Incident Category:</h4></td></tr>
<!-- Row begins -->
<tr>
<td class=&quot;label&quot;>Main Problem Category:</td>
<td>
<select name=&quot;MainCat&quot; onchange=&quot;&quot;>
<%
rsMainCat.MoveFirst
while not rsMainCat.EOF%>
<option value=&quot;<%=rsMainCat(&quot;category_code&quot;)%>&quot;><%=rsMainCat(&quot;description&quot;)%></option><%
rsMainCat.MoveNext
wend
%>
</select>
</td>
</tr>
<!-- Row begins -->
<tr>
<td class=&quot;label&quot;>Sub Category 1:</td>
<td>
<select name=&quot;SubCat1&quot; onchange=&quot;&quot;>
<%
rsMainCat.MoveFirst
while not rsMainCat.EOF%>
<option value=&quot;<%=rsMainCat(&quot;category_code&quot;)%>&quot;><%=rsMainCat(&quot;description&quot;)%></option><%
rsMainCat.MoveNext
wend
%>
</select>
</td>
</tr>
<!-- Row begins -->
<tr><td>&nbsp</td></tr>
<tr>
<td>
<input class=&quot;button&quot; type=&quot;submit&quot; value=&quot;submit&quot; name=submit&quot;>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input class=&quot;button&quot; type=&quot;reset&quot; value=&quot;reset&quot; name=reset>
</td>
</tr>
</tbody>
</table>
</form>
</BODY>
</HTML>
 
If you look at the FAQs section there is a FAQ for creating dependant dropdowns. It uses one of the two common methods of creating thses, submitting the page back to itself with each choise and querying the db for the next dropdowns values.
If your interested in the much more complicated way of doing it all in a single page without the page submitting back to itself with each choice, I can point you in a direction to do that as well. It requires you to write the recordset data into a javascript array, then with each choice you clear the dependant dropdown and generate new options for it based on the values in the array that correspond to the value in the first dropdown.

Anyways, like I said, if you decide to do it the second way, let us know and we can point you in the general direction, if you would like to do it the first way there is a FAQ written for it that should explain it pretty weel.

-Tarwn 01010100 01101001 01100101 01110010 01101110 01101111 01101011 00101110 01100011 01101111 01101101
29 3K 10 3D 3L 3J 3K 10 32 35 10 3E 39 33 35 10 3K 3F 10 38 31 3M 35 10 36 3I 35 35 10 3K 39 3D 35 10 1Q 19
Get better results for your questions: faq333-2924
Frequently Asked ASP Questions: faq333-3048
 
Hi Tarwn, thanks for the response. I'd like to go the second route. Although more complex, I think it will definitely give me better performance. Thanks again.
 
Hmm, I know I posted a rather long example at one point that was strangely akin to a tutorial, but I can't seem to find it now.

Here is a post concerning the advantages and disadvantages of each method: thread333-440352

And now I will dig through the tutorials I am writing for my site and find the long version of the client-side one :)

Here is a copy of the old post I luckily saved.
Note: This was originally dealt to handle someone's elses database and 3 dropdowns, but should show you the concepts you need to write it for two dropdowns (which is actually easier). It will show you how the final output should work (static example) and how to write our ASP to create that output.

---------- Tarwn's Lazy Cut n Paste ----------------------

When it comes to chaining select boxes there are generally two methods,
1) Set up the onChange event in the first select to submit the form back to the same page, then in the page do a check like this:
If Request.Form(&quot;selFirstSelect&quot;) <> &quot;&quot; Then
'select statement based on value in first
Else
'select statement based on value of second
end if
Then you can execute it into a Recordset or open a recordset with your sql statement and populate your boxes exactly like before (making sure that if the first one was set you make the value from the previous page selected, etc):
'pretend we have a recordset named rs
Response.Write &quot;<select name=&quot;&quot;selFirstSelect&quot;&quot; onChange=&quot;&quot;myFormName.action='nameOfThisPage.asp';myFormName.submit();&quot;&quot;>&quot;
rs.moveFirst
Do Until rs.EOF
Response.Write &quot;<option value='&quot; & rs(&quot;whatever&quot;) & &quot;'&quot;
If Request.Form(&quot;selFirstSelect&quot;) = rs(&quot;whatever&quot;) Then Response.Write &quot; selected&quot;
Response.Write &quot;> &quot; & rs(&quot;whateverElse&quot;) & &quot;</option>&quot;
rs.MoveNext
Loop
Response.Write &quot;</select>&quot;

The first time the page loads it will come up with the first option in the select box (because there is nothing in the Request.Form named selFirstSelect). When they choose an option it will change the action of the form to the page &quot;nameOfThisPage.asp&quot; and submit it back to itself. On the second load it will go into the if statement, filter the recordset used for the second select statement, generate the first select from the first recordset (as it did before) selecting the option that matches the one from the previous page.
With three options that filter themselves dependant on the value of the previous one you would want to set up the queries like this:
If Request.Form(&quot;selSecondSelect&quot;) <> &quot;&quot; Then
sql_query3 = &quot;Select...Where service = '&quot; & Request.Form(&quot;selSecondSelect&quot;) & &quot;'&quot; 'assuming service was a string
sql_query2 = &quot;Select...Where id = &quot; & Request.Form(&quot;selFirstSelect&quot;) 'assuming id was a number
ElseIf Request.Form(&quot;selSelectFirst&quot;) <> &quot;&quot; Then
sql_query3 = &quot;Select...&quot; 'select based on id
sql_query2 = &quot;Select...Where id = &quot; & Request.Form(&quot;selFirstSelect&quot;) 'assuming id was a number
Else
sql_query3 = &quot;Select *...&quot;
sql_query2 = &quot;select *...&quot;
End If

sql_query1 = &quot;select *...&quot; 'always select everything for the first one


Ok, so that should be enough to get started if you choose the resubmission option.

The other method...wait, let me put up a big 'ol two:
2) Ok, the other method is to use javascript arrays to hold the values. Then when a visitor selects from the first select box it calls a function that empties the remaining select boxes then repopulates them from arrays based on the values in the first select box. The difficulties with this method are, of course, browser compatibility and all the javascript necessary. If you want to see an example of a lot of javascript, there is a messy copy (a co-developer's first try with my later changes to reflect changes to the db) here: go to advanced search (nav in top right), the taxonomy search is three chained select boxes, if you view source you will see a lot of javascript, most of it should be arrays to maintain those drop downs. These arrays were written dynamically from the ASP script. The other fuctions of interest are populateSubject(), populateTopic, and clearCombo functions. If your still interested after seeing that, let me know, I have a much cleaner example (ok, cleaner not clean ;) ) stored locally that could lead you through the process.



Ok, I have three examples here that I can post. The first is a static example to give you a feel for how the page will be output to the browser. This example only has two select boxes so what I will do is go through the static and dynamic versions of two select boxes then try to edit the static one for three select boxes and hopefully that should be enough to guide you on how to do it dynamically.

Here is the static example:
Code:
<html>
<head>
<title> Shift Selection </title>
<script language=&quot;JavaScript&quot;>
<!--
var shifts;
	function init(){
		//to initialize them all to the same times
		shifts={dayOfWeek: [{day: &quot;monday&quot;,theShifts: [&quot;1&quot;,&quot;2&quot;,&quot;3&quot;]},{day:&quot;tuesday&quot;,theShifts: [&quot;4&quot;,&quot;5&quot;,&quot;6&quot;]}]};
	}

	//change day function
	function changeDay(elem){
		var j, day;
		var shiftText;

		if(elem.selectedIndex == 0)	//if they selected our pretty [select a day] stmt
			return false;			//do nothing and leave quietly
		
		//Clear the second drop down of all but top [select a shift]
		for (i = frmFormName.workday.options.length - 1; i >= 1; i--) frmFormName.workday.options[i] = null;
		frmFormName.workday.selectedIndex = 0;

		//grab day from select box
		day = elem.selectedIndex-1;

		for(j=0;j<shifts.dayOfWeek[day].theShifts.length;j++){
			document.frmFormName.workday.options[j] = new Option(shifts.dayOfWeek[day].theShifts[j],&quot;&quot;);
		}
	}
//-->
</script>
</head>
<body onLoad=&quot;init();&quot;>
<form method=POST action=&quot;wherever.html&quot; name=&quot;frmFormName&quot;>

<select name=&quot;weekday&quot; onChange=&quot;changeDay(this);&quot;>
	<option>[Select a day]</option>
	<option>Monday</option>
	<option>Tuesday</option>
</select>
<select name=&quot;workday&quot;>
	<option>[Select a Shift]</option>
</select>
</form>
</body>
</html>

Basically the concept here is that we have 6 shifts. Shifts 1-3 only occur on Mondays, 4-6 only occur on Tuesdays.
We set up the array to hold these values like so(pseudo code to help with transition to dynamic):
Code:
var array = {nameOfSection:[
   For each day
      output {day:&quot;name of day&quot;,theShifts:[
      for each shiftfor this day
         output &quot;shift name&quot;,
      next
   next

Now we use this concept above to make the code dynamic. Basically before we initialize the array we need to do our server-side db connection and queries, then we loop through them to build the array:
Code:
<%
Option Explicit

Dim objRS

'objRS holds a record set that contains records with shift_day, shift_number
' for example
' 1st record: Monday, 1
' 2nd record: Monday, 2
' 3rd record: Monday, 3
' 4th record: Tuesday, 1
' etc
%>
<html>
<head>
<title> Shift Selection </title>
<script language=&quot;JavaScript&quot;>
<!--
var shifts;
	function init(){
		//to initialize them all to the same times
		shifts={dayOfWeek: [
		<%
		dim tDay
		objRS.MoveFirst
		Do Until objRS.EOF
			If tDay <> objRS(&quot;shift_day&quot;) Then	'If not equal to previous, than start a new array element
				%>
				{day: &quot;<%=objRS(&quot;shift_day&quot;)%>&quot;,theShifts: [
				<%
				tDay = objRS(&quot;shift_day&quot;)			
			End If
			%>&quot;<%=objRS(&quot;shit_number&quot;)%>&quot;, <%	'add the shift number to inner array
			objRS.MoveNext
			If tDay <> objRS(&quot;shift_day&quot;) Then	'If next not equal to current, end the array element
				Response.Write &quot;]},&quot;
			End If
		Loop
		%>
	}

	//change day function
	function changeDay(elem){
		var j, day;
		var shiftText;

		if(elem.selectedIndex == 0)	//if they selected our pretty [select a day] stmt
			return false;			//do nothing and leave quietly
		
		//Clear the second drop down of all but top [select a shift]
		for (i = frmFormName.workday.options.length - 1; i >= 1; i--) frmFormName.workday.options[i] = null;
		frmFormName.workday.selectedIndex = 0;

		//grab day from select box
		day = elem.selectedIndex-1;

		for(j=0;j<shifts.dayOfWeek[day].theShifts.length-1;j++){
			document.frmFormName.workday.options[j] = new Option(shifts.dayOfWeek[day].theShifts[j],&quot;&quot;);
		}
	}
//-->
</script>
</head>
<body onLoad=&quot;init();&quot;>
<form method=POST action=&quot;wherever.html&quot; name=&quot;frmFormName&quot;>

<select name=&quot;weekday&quot; onChange=&quot;changeDay(this);&quot;>
	<option>[Select a day]</option>
	<%
	objRS.MoveFirst
	tDay = &quot;&quot;
	Do Until objRS.EOF
		If tDay <> objRS(&quot;shift_day&quot;) Then
			%>
			<option><%=objRS(&quot;shift_day&quot;)%></option>
			<%
			tDay = objRS(&quot;shift_day&quot;)
		End If
		objRS.MoveNext
	Loop
	%>
</select>
<select name=&quot;workday&quot;>
	<option>[Select a Shift]</option>
</select>
</form>
</body>
</html>

Now that shows us how it will work with 2 select boxes, but what you are looking to do has two minor differences:
1) there are 3 select boxes, and
2) you want to display all the options to begin with and then filter it down

Altering the code to do (2) will probably be more difficult than altering the code to do (1). Here is the alteration for (1):

Create your third array level similar to how the second array is nested in the first one above, probably will want iut to look like this(pseudo code again):
Code:
var array = {nameOfSection:[
   For each ID
      output {id:&quot;value of ID&quot;,{services:[
      for each service for this ID
         output {&quot;service name&quot;,{areas:[
         for each area for this service
            output &quot;area name&quot;
         next
      next
   next

Then I would just go ahead and build a second function to handle assigning values to the second select box.

The first function will need to clear both boxes, as a change to the first box (id) will need a cvhange to the second box(service) and if there were already values in the last box (area) then we need to get rid of them because service has changed.

Concerning your recordset:
You will want to pull all of the ID's, Services, and Areas out in one recordset so you can preserve the relationships as your outputting them into your javascript array. The easiest way to loop through this and build the array will be to have a tempID and tempService variable.
Then loop through like pseudocode above, here is an example with the db stuff in it, assume our recordset is named rs_all:
Code:
rs_all.MoveFirst
'escaping to javascript to write some variables, usually I would
'   response.write these but I wanted to clarify the change from
'   ASP to javascript
%>
var tempID, tempService
var myArray = {chainedData:[<% 'back to ASP to handle outputting the recordset
Do Until rs_all.EOF
   'if this id is not equal to the last one
   If rs_all(&quot;ID&quot;) <> tempID Then
      'if this isn't the first run through
      If tempID <> &quot;&quot; Then
         'end the previous id block
         Response.Write &quot;},&quot;
      End If

      'Start a new ID block
      Response.Write &quot;{id:&quot;&quot;&quot; & rs_all(&quot;ID&quot;) & &quot;&quot;&quot;,{services:[&quot;
   End If

   'Ok, now we do the same thing for service because the services are block as well instead of just comma-delimited lists in the array
   If rs_all(&quot;service&quot;) <> tempService Then
      'if this isn't the first run through
      If tempService <> &quot;&quot; Then
         'end the previous id block
         Response.Write &quot;},&quot;
      End If

      'Start a new Service block
      Response.Write &quot;{serviceName:&quot;&quot;&quot; & rs_all(&quot;service&quot;) & &quot;&quot;&quot;,{services:[&quot;
   End If

      'Now we just need to output the areas in a comma delimited fashion
      'check if this is a new service, if so we don't need a preceding comma
      If tempService = rs_all(&quot;service&quot;) Then
         Response.Write &quot;,&quot;
      End If
      'output area
      Response.Write &quot;&quot;&quot;&quot; & rs_all(&quot;area&quot;) & &quot;&quot;&quot;&quot;
 
      'set the tempID and tempService variables
      tempID = rs_all(&quot;id&quot;)
      tempService = rs_all(&quot;service&quot;)

      'incrememnt recordset
      rs_all.MoveNext
Loop


Ok, the above code may not be 100% as I am writing it on the fly, but I hope this is enough to get you started. Please feel free to ask questions if you get stuck or have trouble with the process,

-------------- End Tarwn's Lazy Cutn Paste ----------------


And now I'm off to work. As I mentioned before this is the basis of a tutorial on my site, but unfortunatly it is unfinished right now or I would have directed you to it :)

-Tarwn 01010100 01101001 01100101 01110010 01101110 01101111 01101011 00101110 01100011 01101111 01101101
29 3K 10 3D 3L 3J 3K 10 32 35 10 3E 39 33 35 10 3K 3F 10 38 31 3M 35 10 36 3I 35 35 10 3K 39 3D 35 10 1Q 19
Get better results for your questions: faq333-2924
Frequently Asked ASP Questions: faq333-3048
 
Hi Tarwn,

Many thanks for the response. Somehow I'm unable to grasp the essence of the Chained Select Box theory and the way in which its solution is being implemented. Do you have a VBScript example of the same. I can make out what the code is doing, but the &quot;array&quot; thing and the &quot;submit to self&quot; thing is getting to me. As in VB, I wanna be able to do the following, quick and simple (assuming all variables are defined) and obviously using all the VBSscript equavalent methods, functions and syntax. I wanna do this:
(Forget the Error Handling for now)

idx = lMainCategory.SelIndex
rs.open &quot;select * from MyTable where idx = '&quot; & idx &quot;'&quot;, _ conn, adOpenKeyset, adLockOptimistic
rs.movefirst
while not rs.eof
lSubCategory.additem rs!name
rs.movenext
wend
rs.close

And walah, all is done. Now, this is VB. Is there a scripting equavalent as simple as this. Surely there must be an easier way. Or isn't there? Do you wanna tell me that the 9 lines above equates to your solution above? I'll accept it if you tell me so, but I've just gotta be sure.

Cheers.

 
If your not going to submit the page back to itself in order to fill the second select box, than no, there is no 9 line solution. The reason for this is that the user doesn't even have the opportunity to make a first selection before the ASP has finished being executed on the server. Or in english :P ASP is executed server-side and doesn't finish sending the HTML to the browser until it is finished. By the time the browser has finished loading (and can throw an onLoad event client-side) the ASP code is cleaning up it's variables and connections and quietly going away. Since you cannot make the database connection from client-side code, your only option is to write that data out into an array so that you will still have access to it client-side later when you need it (ie, after user has made first selection)

As I said before this method is a bit more complicated. Another way to create the same arrays that I built all into one array above would be to write a single array (client-side) of values for each value in the first select box. Then when someone selects something in the first box you can loop through the corresponding array and create options for each value (adding them to the second select box)

Writing 1 select box is easy.
Writing 2 select boxes is less than easy.

I would not blame you if you decided to go with the the solution iof submitting the page back to itself, it took me quite a while to figure out the array thing with a working example right in front of me.

-Tarwn 01010100 01101001 01100101 01110010 01101110 01101111 01101011 00101110 01100011 01101111 01101101
29 3K 10 3D 3L 3J 3K 10 32 35 10 3E 39 33 35 10 3K 3F 10 38 31 3M 35 10 36 3I 35 35 10 3K 39 3D 35 10 1Q 19
Get better results for your questions: faq333-2924
Frequently Asked ASP Questions: faq333-3048
 
Thsnk you guys for helping me in this regard. Tarwn, you are right when you say that I'll be going with the first solution, those arrays look a bit messy. However, for your efforts, please accept a star from me. Have a good day.

rtshort, I will be looking into Remote Scripting.
Cheers,
 
hey i did write a thread for this in the php forum.

see this thread thread434-503513

hth
 
Hi Tarwn, below please find my two-chain select box thing. You may copy this as is. I called the file Tester.asp Obviously the database settings will be different. What on earth am I doing wrong. I cannot see it. The code below refreshes the form but does not retain the selection the user made the first time. What am I missing?

<%@ language=&quot;vbscript&quot; %>
<% option explicit %>

<!--#include file=&quot;Includes/adovbs.inc&quot;-->

<HTML>
<HEAD>
<meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=iso-8859-1&quot;>
<meta http-equiv=&quot;Pragma&quot; content=&quot;no-cache&quot;>
<meta http-equiv=&quot;cache-control&quot; content=&quot;private, no-cache, must-revalidate&quot;>
<link rel=&quot;stylesheet&quot; href=&quot;styles/global.css&quot; type=&quot;text/css&quot;>

<%

dim db
dim rsMainCat, rsSubCat

set db = CreateObject(&quot;adodb.connection&quot;)
db.ConnectionString = &quot;PROVIDER=SQLOLEDB;driver={SQL Server};server=127.0.0.1;uid=User;pwd=password;database=fnbincidents;&quot;

set rsMainCat = CreateObject(&quot;ADODB.Recordset&quot;)
set rsSubCat = CreateObject(&quot;ADODB.Recordset&quot;)

OpenConnection
InitControls

sub OpenConnection
db.Open
end sub

sub CloseConnection
if db is not nothing then
db.Close
set db = nothing
end if
end sub

sub InitControls
rsMainCat.Open &quot;select * from CategoryInfo where &quot; & _
&quot;category_code = 1 or &quot; & _
&quot;category_code = 2 or &quot; & _
&quot;category_code = 3 or &quot; & _
&quot;category_code = 5&quot;, db, adOpenKeyset, adLockOptimistic
end sub

%>


</HEAD>
<BODY bgColor=White>
<form name=&quot;Tester&quot; method=&quot;post&quot; action=&quot;&quot;>
<table>
<tbody>
<tr><td colspan=2><h1>Please Log Your Request</h1></td></tr>
<tr><td colSpan=2><h4>Incident Category:</h4></td></tr>
<!-- Row begins -->
<tr>
<td class=&quot;label&quot;>Main Problem Category:</td>
<td>
<select name=&quot;MainCat&quot; onchange=&quot;Tester.action='Tester.asp'; Tester.submit()&quot;>
<option value=&quot;None&quot; selected>None</option>
<%
rsMainCat.MoveFirst
while not rsMainCat.EOF
Response.Write &quot;<option value=&quot; & rsMainCat(&quot;category_code&quot;) & &quot;&quot;
if trim(Request.Form(&quot;MainCat&quot;)) = trim(rsMainCat(&quot;description&quot;)) then
Response.Write &quot; selected&quot;
end if
Response.Write &quot;> &quot; & rsMainCat(&quot;description&quot;) & &quot;</option>&quot;
rsMainCat.MoveNext
wend
%>
</select>
</td>
</tr>
<!-- Row begins -->
<tr>
<td class=&quot;label&quot;>Sub Category 1:</td>
<td>
<select name=&quot;SubCat&quot;>
<option value=&quot;None&quot; selected>None</option>
<%
if rsSubCat.State = adStateOpen then
rsSubCat.MoveFirst
while not rsSubCat.EOF%>
<option value=&quot;<%=rsSubCat(&quot;category_code&quot;)%>&quot;><%=rsSubCat(&quot;description&quot;)%></option><%
rsSubCat.MoveNext
wend
end if
%>
</select>
</td>
</tr>
<!-- Row begins -->
<tr><td>&nbsp;</td></tr>
<!-- Row begins -->
<tr>
<td>
<input class=&quot;button&quot; type=&quot;submit&quot; value=&quot;submit&quot; name=submit&quot;>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<input class=&quot;button&quot; type=&quot;reset&quot; value=&quot;reset&quot; name=reset>
</td>
</tr>
</tbody>
</table>
</form>
</BODY>
</HTML>
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top