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 sizbut on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

dynamic listbox problems

Status
Not open for further replies.

moley

IS-IT--Management
Mar 26, 2002
95
GB
Hi,

I'm trying to get my listboxes to work with the following data:

rsWT is my recordset

WorkTypeID WorkType AssessCategoryID AssessCategory
1 Telephone 1 Energy
1 Telephone 2 Service
2 Correspondence 1 Energy
2 Correspondence 1 Energy

The code is

<script Language="JavaScript">

// start of listbox array
var WorkType;
var WorkTypeOption = new Array();
function init(){
//to initialize
WorkTypeOption ={WorkTypeList: [
<%
dim tWorkType
dim tAssCategory
rsWT.MoveFirst

Do Until rsWT.EOF
If tWorkType <> rsWT("WorkTypeID") Then 'If not equal to previous, than start a new array element
%>
{WorkType: "<%=rsWT("WorkTypeID")%>",AssCategory: [
<%
tWorkType = rsWT("workTypeID")
End If

Response.Write """" & rsWT("AssessCategoryID") & ";" & rsWT("AssessCategory") & """" 'add the assessment category to inner array


rsWT.MoveNext

'end array block
If Not rsWT.EOF Then
'If block completed
If tWorkType <> rsWT("workTypeID") Then 'If next not equal to current, end the array element
Response.Write "]},"
Else
'put in comma, add next element
Response.Write ","
End If
Else
'finish the last block
Response.Write "]}"
End If
Loop
'end the whole array
Response.Write "]};"
%>
}

//change day function
function changeAssCat(elem){
var j, workType, cboAssCat;

cboAssCat = document.frmAssess.cboAssCat


if(elem.selectedIndex == 0)
return false;
cboAssCat.options.text = new Option("Please Select","")
//Clear the second list box
for (i = cboAssCat.options.length; i >= 1; i--) cboAssCat.options[i-1] = null;
cboAssCat.selectedIndex = 1;

//get work type
cboAssCat = elem.selectedIndex=0;
alert (cboAssCat);
//
for(j=0; j<WorkTypeOption.WorkTypeList[WorkType].AssCategory.length; j++){
cboAssCat.options[j] = new Option(WorkTypeOption.WorkTypeList[WorkType].AssCategory[j],"");
}
}

With the code in the body:

<tr>
<td width="300" height="25">
<div align="right">Work Type:
<select name="cboWrkType" class="tlb" onChange="changeAssCat(this);">
<option>Please select</option>

<%
rsWT.MoveFirst
tWorkType = ""
Do Until rsWT.EOF
If tWorkType <> rsWT("workTypeID") Then
%>
<option value ="<%=rsWT("workTypeID")%>"><%=rsWT("workTyp")%></option>
<%
tWorkType = rsWT("workTypeID")
End If
rsWT.MoveNext
Loop
%>
</select>
</div>
</td>
</tr>
<tr>
<td width="300" height="25">
<div align="right">Assessment Category:
<select name="cboAssCat" class="tlb">
<option>Please Select </option>
</select>
</div>
</td>
</tr>
<tr>

I'm getting an error :

error 'worktypeoption.worktypelist' is null or not an object

Can anyone shed some light????

Thanks
 
Look through the tutorials written in the FAQs ( under "Dynamic List Boxes"

If you still have questions, let us know.

Programming today is a race between software engineers striving to build better and bigger idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning. - Rick Cook (No, I'm not Rick)

zen.gif
 
Actually it looks like he mayu have followed my FAQ :p

CAn I see some sample output (from view source) to see what the javascript arrays look like after they have been generated? (if you have 5 million items, i'd prefer not to see them all :) )

01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111
Need an expensive ASP developer in the North Carolina area? Feel free to let me know.


 
this is the array from the ie source, which looks fine as far as I can see.

WorkTypeOption ={WorkTypeList: [

{WorkType: "1",AssCategory: ["1"]},
{WorkType: "2",AssCategory: ["1"]}]};
 
And I've tried to modify your code to get this to work, although this is quite new to JS so i'm bound to have made a blunder or two. Is there a reason why you didnt set var shifts as New Array()?

thanks

Moley
 
I've also taken out "& rsWT("AssessCategory") &" just to get it working so the array should look like
WorkTypeOption ={WorkTypeList: [

{WorkType: "1",AssCategory: ["1;Telephone"]},
{WorkType: "2",AssCategory: ["1;Telephone"]}]};

I'll be adding more data once it working

cheers
 
onLoad="init();" mmmmm, i guess this would help!!!

Thanks, problem solved!
 
Tarwn,

Any chance you could show me how you would add a value to the second listbox from your facts. i'm still having problems.

shifts={dayOfWeek: [{day: "monday",theShifts: ["1","2","3"]},{day:"tuesday",theShifts: ["4","5","6"]}]};



Thanks again

Moley
 
Ok, that was written quite a while ago, I'm no more then a medium javascript person and then I was less, which is why I didn't write it using new Arrays (which I probably would have done had I written it recently).

Basically the array is a little complicated because of the inner definitions. Probably a bit to complicated for a tutorial not on javascript arrays. I think I will change it to lower future confusion. The inner defintions on those arrays are what allow us to reference them by a meaningful name rather than simply have multiple numeric indexes chained together.

Taking the example of
shifts={dayOfWeek: [{day: "monday",theShifts: ["1","2","3"]},{day:"tuesday",theShifts: ["4","5","6"]}]};

This was perhaps a badly written example, bu I will use it anyway to help understand it better.
We have an aray named shifts. This array is an assocative array, most of which is unused but only there for readability. shifts itself is not really an array, or it is an array with only one value. See why this isn't good example? Rather than continue I'll give you an example using new Array.

The first decision we have to make will directly affect how many levels of arrays we are dealing with. We have to decide whether the values from the first dropdown are going to be included in the array or assumed based on their index in the dropdown. If we are going to assume the indexes then we need an array with number of dimensions = number of dropdowns we plan to have. If we are going to build it in, then number of dropdowns + 1.

Lets go by the assumption model, I'll leave the non-assumption model for another time:
The one thing we can't overlook here is that the very first element of the dropdown is going to be used for some kind of generic selection text like "[ Select An Item ]" so we either compensate by adding a null entry as the 0th element on the highest array or we deal with the offset in our function that populates later dropdowns. I prefer to keep things lined up, so we will add a null value.

[0] = undefined
[1][0] = undefined
[1][1] = mondays 1
[1][2] = mondays 2
[1][3] = mondays 3
[2][0] = undefined
[2][1] = tuesdays 1
etc...

I leave the first element of each inner array as undefined so that if we have multiple dropdowns they will all consistently allow for an empty zero-th element.

To build an array like this will take a little work, but should be easier to understand then the mish-mash I had before. Lets throw out the example I had before and start with a clean slate (I'll re-use this when I rewrite the FAQ).

For our example assume you have a table (or associated tables) that have data for cases of paper. We will have multiple types of paper and then multiple grades of paper for each type. Assume our data comes back from the database in a recordset like:
Code:
Paper.paper_type   PaperGrades.paper_grade
Printer            Standard 8.5x11
Printer            Glossy Photo Paper 5x7
Printer            Ultra-Super-Fine 8.5x11
Printer            Ultra-Glossy Photo Paper 5x7
LooseLeaf          Yellow Standard Rule 8.5x11
LooseLeaf          Yellow Legal Rule 8.5x11
LooseLeaf          White Legal Rule 8.5x11
Photocopy          Standard 8.5x11
Photocopy          Super recycled 8.5x11
Photocopy          Barely Better Then Toilet Paper 8.5x11
Photocopy          Thicker Then Cardcoard 8.5x11

So what we will want to do is loop through this recordset to build the data array then loop through it again to build the first select box (technically we could do it at the same time to save processing power, but that would add confusion to the code).

Lets build the array, we will assume our recordset is called rsPaper:
Code:
<script language="javascript">
var dataArray = new Array(<%
   If Not rsPaper.EOF Then rsPaper.MoveFirst
   Dim last_item
   Do Until rsPaper.EOF
      'check if the first column item is equal to it's value  
      '   from the previous loop, if not start a new array
      If last_item <> rsPaper("paper_type") Then
         'if there was a last item, finish the previous array
         If len(last_item) > 0 Then Response.Write ")"
         'start a new array
         Response.Write ",new Array("
         'record last item
         last_item = rsPaper("paper_type")
      End If

      'output the second column value preceded by a comma
      Response.Write "," & rsPaper("paper_grade")

      'queue to next record
      rsPaper.MoveNext
   Loop

   'finish open array if there was a last item
   If len(last_item) > 0 Then Response.Write ")"
   %>);

Now that we have our array built we need a function to change options that will be called from our first dropdown:
Code:
function changeOptions(elemOne,elemTwo){
   var i;

   //clear out previous options leaving the top generic text
   for(i = elemTwo.options.length; i >= 1; i--)
      elemTwo.options[i] = null;
   elemTwo.selectedIndex = 0;

   //if the selected index in the first one is 0 escape out
   if(elemOne.selectedIndex == 0)
      return false;

   //populate second one
   for(i=1;i<dataArray.length;i++){
      elemTwo.options[i] = new Option(dataArray[elemOne.selectedIndex][i],elemOne.selectedIndex][i]);
   }
}
</script>

Now this isn't instantly scalable to a three tier select set, but it is close.

taking this one step further and adding id/value pairs like you wanted to do means that we have to add an additional level of depth to our array or use easily plit strings for our array values.

To use the additional array level will require only minimal changes, so I will makethem and highlight them with comments:
Code:
<script language="javascript">
var dataArray = new Array(<%
   If Not rsPaper.EOF Then rsPaper.MoveFirst
   Dim last_item
   Do Until rsPaper.EOF
      'check if the first column item is equal to it's value  
      '   from the previous loop, if not start a new array
      If last_item <> rsPaper("paper_type") Then
         'if there was a last item, finish the previous array
         If len(last_item) > 0 Then Response.Write ")"
         'start a new array
         Response.Write ",new Array("
         'record last item
         last_item = rsPaper("paper_type")
      End If

      'output the second column value preceded by a comma
      Response.Write ",[highlight]new Array(" & rsPaper("grade_id") & "," & rsPaper("paper_grade") & ")"[/highlight] 'Change [0]

      'queue to next record
      rsPaper.MoveNext
   Loop

   'finish open array if there was a last item
   If len(last_item) > 0 Then Response.Write ")"
   %>);

function changeOptions(elemOne,elemTwo){
   var i;

   //clear out previous options leaving the top generic text
   for(i = elemTwo.options.length; i >= 1; i--)
      elemTwo.options[i] = null;
   elemTwo.selectedIndex = 0;

   //if the selected index in the first one is 0 escape out
   if(elemOne.selectedIndex == 0)
      return false;

   //populate second one
   for(i=1;i<dataArray.length;i++){
      elemTwo.options[i] = new [highlight]Option(dataArray[elemOne.selectedIndex][i][1],elemOne.selectedIndex][i][0]);[/highlight] 'Change [1]
   }
}
</script>

Change [0]: Instead of adding just a single value for each garde we now add a two element array of id, value
Change [1]: We still use the value for the text of each new option, but now we use the id for the value


Building the dropdown should be fairly simple as long as you remember that we planned ahead to add a generic [Select an Item] text option to the top of each dropdown.

Since I have seen others have difficulties with the FAQ in the past and even I have some difficultis with the keyed and named arrays system i was using, I will be changing it shortly to cover everything I covered in this post as well as multiple chained dropdowns. I apologize for any confusion and hope this helps,

-T

01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111
Help, the rampaging, spear-waving, rabid network gnomes are after me!
 
Thanks Tarwn,

Is this the desired array, cause i've still got a few bugs?

Code:
var dataArray = new Array(,new Array(,new Array(1,Outbound),new Array(2,Inbound),new Array(3,Written),new Array(4,Outbound Email),new Array(5,Inbound Email)),new Array(,new Array(1,Outbound)));
 
That looks right, except for one thing. You need to put some quotes in there so that your strings will be treated as strings, otherwise your going to be getting a lot of undefineds or errrors all over the place when it tries to read them as undeclared variables.

-T

01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111
Help, the rampaging, spear-waving, rabid network gnomes are after me!
 
T
I've updated the arrays with quotes but I get a syntax error on the array.
Code:
new Array(,new Array(,new Array("1","Outbound"),new Array("2","Inbound"),new Array("3","Written"),new Array("4","Outbound Email"),new Array("5","Inbound Email")),new Array(,new Array("1","Outbound")));

Any ideas???
Thanks for your help.

Cheers
 
Argh, my mistake...working with to many languages recently and overlooked something somewhat obvious, javascript wants values before those leading parans, so add in "null"'s and it should stop complaining :p
Code:
<script language="javascript">
var dataArray = new Array([highlight]null[/highlight]<%
   If Not rsPaper.EOF Then rsPaper.MoveFirst
   Dim last_item
   Do Until rsPaper.EOF
      'check if the first column item is equal to it's value  
      '   from the previous loop, if not start a new array
      If last_item <> rsPaper("paper_type") Then
         'if there was a last item, finish the previous array
         If len(last_item) > 0 Then Response.Write ")"
         'start a new array
         Response.Write "[highlight]null[/highlight],new Array("
         'record last item
         last_item = rsPaper("paper_type")
      End If

      'output the second column value preceded by a comma
      Response.Write ",new Array(" & rsPaper("grade_id") & "," & rsPaper("paper_grade") & ")"

      'queue to next record
      rsPaper.MoveNext
   Loop

   'finish open array if there was a last item
   If len(last_item) > 0 Then Response.Write ")"
   %>);

function changeOptions(elemOne,elemTwo){
   var i;

   //clear out previous options leaving the top generic text
   for(i = elemTwo.options.length; i >= 1; i--)
      elemTwo.options[i] = null;
   elemTwo.selectedIndex = 0;

   //if the selected index in the first one is 0 escape out
   if(elemOne.selectedIndex == 0)
      return false;

   //populate second one
   for(i=1;i<dataArray.length;i++){
      elemTwo.options[i] = new Option(dataArray[elemOne.selectedIndex][i][1],elemOne.selectedIndex][i][0]);
   }
}
</script>

01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111
Help, the rampaging, spear-waving, rabid network gnomes are after me!
 
Argh again, that should have said either "After the leading parans" or "Before the leading commas", good thing I'm not coding right now, it would be a mess :)

01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111
Help, the rampaging, spear-waving, rabid network gnomes are after me!
 
Tarwn,

Thanks for all your time, i'm just abount there now. One last thing, when you call the changeOptions(elemOne, elemTwo), what is the syntax for the onChange?? is it onChange="changeOptions(this)" ?

Thanks again, I'll stop harassing you now!

Cheers

Moley
 
I put both in there so I wouldn't have to guess at form names and such. basically you would call it with a reference to the first select and a ref to the second select. So something like:
Code:
onClick="changeOptions(this,document.frmname.select2Name);"
With frmName being replaced with the name of your form and select2name being replaced with the name of your second select.

-T

01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111
Help, the rampaging, spear-waving, rabid network gnomes are after me!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top