Link to home
Start Free TrialLog in
Avatar of cmaries
cmaries

asked on

Connected Drop Down Menus

I am looking to create five connected drop down menus.  This is a search of various tables of MySql DB.  ==>The fist drop down menu will have {Shape, Color, Texture}.  For this example lets say a person selects "Color".

==>The second menu will have fill with the results of that DB, i.e. if it will fill with {Blue, Red, Yellow, Green}. This is product is the result of an SQL statement like 'Select Color_id, Color_name from T_Colors';
Once the user selects a color, let say 'Red',  at the bottom of the screen all the items in the DB that are "Red" will print out.  'Select * from T_Items where Color="Red";

==>The 3rd, 4th, and 5th drop downs are used to narrow the search down.
The 3rd menu will be {Shapes} and will only hold the shapes that are Red. {Round, Square, Triangle}
The 4th menu will be blank because Color is your original search parameter.
The 5th menu will be {Texture} and will only how the textures that are Red.  {Rough, Sandy, Smooth}

This will effect the results (at the bottom of the screen).  If the user selects Square, then the results refresh and only show items that are Square and Red.   If the user selcects Triangle and Smooth, then the results refresh and only show items that are Red, Triangle and Smooth.

Something similar to http://dynamicdrive.com/dynamicindex1/chainedmenu/ .  I am willing to set this up with a display button for menu 3, 4 and 5.
I am trying to do this with PHP and HTML and I am struggling with the refreshes.  I am wiling to bring in some AJAX but I am really really new to it.

Please Please help!  
 
ASKER CERTIFIED SOLUTION
Avatar of hielo
hielo
Flag of Wallis and Futuna image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of cmaries
cmaries

ASKER

I have been tracing your code.  I understand the onChange is set to a JS function that calls a php file.  Now in my PHP file I list.   It performs the SQL select and outputs a the second drop down.  How do I control where it is placed in the original file?


while ($GroupListItem = mysql_fetch_array($results)) {
	$group_id = $GroupListItem["SHAPE_ID"];
	$group_title = $GroupListItem["SHAPE_TITLE"]; 
			
?>
<select name="SubGroup" style="width:15em; background-color:#D8D8D8">
        <option>Group Items</option>
        <option value="<? echo($group_id); ?>"><? echo($group_title); ?></option> <?
}
?>
</select>

Open in new window

>>How do I control where it is placed in the original file?
If you look carefully you will see:
function fetchData(url,targetElem){
...
xmlHttp.onreadystatechange=function(){stateChanged(targetElem);};
}
The first argument is  the url to where the AJAX request should be made. The second argument is basically an 'identifier' so that I know at what point or when or from where I called fetchData. So, when the server finishes sending the data back, it will call the function named stateChanged() and will pass the identifier that was originally supplied to fetchData. So, when I call:
fetchData("lilyyan.php?action=step1","step1");
An ajax request will be made to this url => lilyyan.php?action=step1
and when it cumpletes the fullowing function calle will be made =>stateChanged("step1")

SO in stateChanged all you need to know is "who" made the ajax request, and depending on who it was you choose which section of your page should be updated. That's what the switch inside the stateChanged function is doing. It is "figuring out" which element triggered the AJAX call and once it finds out, it updates the appropriate section.

NOTE: Since the user needed to make AJAX call every time the user picked a different option, I ended up sending the select markup with the onchange event handler so that it would make the necessary ajax call:
printf "<select name='action1' id='action1' onchange='fetchData(\"lilyyan.php?action=step2&selection=\"+this.value,\"step2\")'>...</select>";

Which when received by the browser it sees:
<select name='action1' id='action1' onchange='fetchData("lilyyan.php?action=step2&selection="+this.value,"step2")'>...</select

Hope this is clear
Avatar of cmaries

ASKER

Mine is based on the link you suggested and I don't see the line you are referring to.  I do have a "xmlHttp.onreadystatechange=stateChanged".  I am not getting an error but nothing is happening after I make a select in the first pull down.  I have attached the js file.  

Could you post a simple example that pulls from a db with a 3 level chain?
var xmlHttp
 
function showUser1(str)
{ 
xmlHttp=GetXmlHttpObject()
if (xmlHttp==null)
 {
 alert ("Browser does not support HTTP Request")
 return
 }
var url="getmenu1.php"
url=url+"?q="+str
url=url+"&sid="+Math.random()
xmlHttp.onreadystatechange=stateChanged 
xmlHttp.open("GET",url,true)
xmlHttp.send(null)
}
 
function stateChanged() 
{ 
if (xmlHttp.readyState==4 || xmlHttp.readyState=="complete")
 { 
 document.getElementById("txtHint").innerHTML=xmlHttp.responseText 
 } 
}
 
function GetXmlHttpObject()
{
var xmlHttp=null;
try
 {
 // Firefox, Opera 8.0+, Safari
 xmlHttp=new XMLHttpRequest();
 }
catch (e)
 {
 //Internet Explorer
 try
  {
  xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
  }
 catch (e)
  {
  xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
  }
 }
return xmlHttp;
}

Open in new window

>>I am not getting an error but nothing is happening after I make a select in the first pull down.
Most like you do not have:
<select onchange="fetchData(...)">

>>Could you post a simple example that pulls from a db with a 3 level chain?
You need to take if one step at a time. First get the script to send request to the server upon selection change. Once you have this figured out then worry about querying the db. I suggest you copy the two files that I did on the suggested link to your server and see it in action. Specifically, I highly recommend you install the Firebug extension on Firebug and watch the data that goes back an forth between browser and server.

Based on this " I don't see the line you are referring to.", I suspect that you are looking for <select...> on the "origininal" html code, but on the example, all the <select...> HTML markup is sent to the browser by the server as the result of AJAX requests. If you look again, you will find this:
window.onload = init;
function init()
{
      fetchData("lilyyan.php?action=step1","step1")
}
which basically says: as soon as the browser finishes loading, execute the init function. Then all that init does is make an ajax request. This request is uniquely identified as step1 so that when stateChanged is called we know what to do with the response based on the identifier. If you examine the php, you will notice that when action=='step1' some specific data is sent. In this case, the server sends the html markup for the first drop-down list:
Select a Month:
<select name='action1' id='action1' onchange='fetchData("lilyyan.php?action=step2&selection="+this.value,"step2")'>
<option value='1'>Jan</option>
<option value='2'>Feb</option>
<option value='3'>Mar</option>
<option value='4'>Apr</option>
<option value='5'>May</option>
<option value='6'>Jun</option>
<option value='7'>Jul</option>
<option value='8'>Aug</option>
<option value='9'>Sep</option>
<option value='10'>Oct</option>
<option value='11'>Nov</option>
<option value='12'>Dec</option>
</select>

I don't mind helping you at all, but what you are asking is basically what I did already. You need to understand that example before continuing. Otherwise, down the road you will not be able to give support that page, or at least, will have a difficult time doing so.
Avatar of cmaries

ASKER

Thank you for the breakdown, :)
I am tracing through yours and mapping mine in a simular fashion.  I do have a few questions.
In "lilyann.php" you send the selection of the previous menu to the next switch with the line
switch( strval($_REQUEST['selection']) ).
In the third menu,  I want to send in the selection made in the first menu AND the selection made in the second menu.  And ultimately I will need the values from all five menus to use in a search.  
Any suggestions?
 
If you look at the onchange even handler for that example you will see this:
fetchData("lilyyan.php?action=step3&selection="+this.value,"step3")

Specifically, the:
"...selection="+this.value

is that part that completes the querystring so that the script knows which option on "this" field was selected. For your purposes, you can substitute "this.value" with a function call. So you will need to create a function an pass it a comma delimited string of the id values of your select lists. Then use those ids to get the values of the other select lists and finally return a queryestring-formatted string. I attached the function below. On my example that would be included in lilyyan.html. NOTE: it requires the arguments to be ids. So, if you currently are sending:
<select name="shape">...</select>
<select name="color">...</select>, etc,

you will need to give each of these select lists a unique id.
<select name="shape" id="selShape">...</select>
<select name="color" id="selColor">...</select>

Meaning no other element on the page would have the same id at any time, even those added/inserted later dynamically.

With that markup in place and with the function attached below, you would send those values as follows:

fetchData("lilyyan.php?action=step3&" + getSelections("selColor,selShape,selShapes"), "step3")

assuming of course you have three select list with those ids. The function below will return a string similar to:
selColor=blue&selShape=rectangle&selShapes=6

which means that the server will ultimately see  this:
lilyyan.php?action=step3&selColor=blue&selShape=rectangle&selShapes=6
which is exactly what you need.
IMPORTANT: the id's of the <select> list are what you will now see on the server. It is perfectly legal to give you select lists an id that is the same as the name attribute as long as there is not other element with the same id.
<select name="shape" id="shape">...</select>
<select name="color" id="color">...</select>

var xmlHttp=null;
function getSelections(elementList)
{
	var elementList=elementList.split(",")
	var params = "";
	for(var i=0,limit=elementList.length; i < limit; ++i)
	{
		params += "&"+elementList[i]+"="+escape(document.getElementById(elementList[i]).value);
	}
return params.substring(1);
}

Open in new window

Avatar of cmaries

ASKER

I changed onchange='fetchData(\"TheFile.php?action=step3&selection2=\"+this.value,\"step3\")'
to
onchange='fetchData("TheFile.php?action=step3&"+getSelections("GROUP,SUBGROUP"),"step3")'
and I am getting the error

Parse error: parse error, unexpected T_STRING in /thepath/TheFile.php on line 62.  It was fine before the change. but was only sending the last variable where I need the first selection also.

The full line is
<select name='SUBGROUP' onchange='fetchData("TheFile.php?action=step3&"+getSelections("GROUP,SUBGROUP"),"step3")'  id='SUBGROUP'>

And before you ask...I did add the getSelections function. :)
>>And before you ask...I did add the getSelections function
Funny. I was not going to ask you that. I was going to ask you if this:
onchange='fetchData("TheFile.php?action=step3&"+getSelections("GROUP,SUBGROUP"),"step3")'

is part of printf. Ex:
printf"
<select onchange='fetchData("TheFile.php?action=step3&"+getSelections("GROUP,SUBGROUP"),"step3")'>
"

I am willing to bet a whole penny that it is. In which case you need to escape the quotation marks with a slash because the scripting engine is getting confused by the quotes of printf and those of your onchange statement. So any double quotes within printf should be preceded by a slash if printf starts and end with double quotes:
printf"<select
onchange='fetchData(\"TheFile.php?action=step3&\"+getSelections(\"GROUP,SUBGROUP\"),\"step3\")'
...
</select>
";

IF your printf starts and ends with apostrophes, the same "escaping" logic would apply, but you would need to escape the apostrophes instead of the double quotes.
Avatar of cmaries

ASKER

You deserve that expert title.... :)
Thank you so much.

Let me add an addition facet to this.  If I want to disable the drop down menu selection (or aka lock it in) after a selection is choosen.  I have seen it done with the onChange  and on rare occasion with onBlur and onFocus.  I don't want to do something that will undo or interfere with the present onChange in place.