Bhavesh
Bhavesh

Reputation: 4677

Populating two dropdowns at once using Ajax

I have three HTML DropDownList (<select><option></option></select>). The first DropDownList contains categories, the second one contains subcategories of different products and the third one contains brands (or manufacturers).

When a category is selected, two drop downs subcategory and brand should be populated at once from the database according to the category id being passed to an Ajax function. I'm using the following Ajax code.

function ajax()
{
    if(window.XMLHttpRequest)
    {
        xmlhttp=new XMLHttpRequest();
    }
    else
    {
        xmlhttp = new ActivexObject("Microsoft.XMLHTTP");
    }
}

function getBrandList(selected)  //selected is the category id.
{               
    ajax();
    xmlhttp.onreadystatechange=function()
    {
        if(xmlhttp.readyState==4 && xmlhttp.status==200)
        {
            document.getElementById("brandList").innerHTML=xmlhttp.responseText;            
        }
    }

    xmlhttp.open("GET","ajax/BrandAjax.php?selected="+selected, true);
    xmlhttp.send();     
    alert(selected);            
}

function getSubcategoryList(selected) //selected is the category id.
{                       
    getBrandList(selected); //First above function is invoked to populate brands.
    ajax();
    xmlhttp.onreadystatechange=function()
    {
        if(xmlhttp.readyState==4 && xmlhttp.status==200)
        {
            document.getElementById("subCategoryList").innerHTML=xmlhttp.responseText;                              
        }
    }

    xmlhttp.open("GET","ajax/SubCatAjax.php?selected="+selected, true);
    xmlhttp.send();             
}   

When a category is selected, the getSubcategoryList(selected) Javascript function is invoked which does the Ajax request. The problem is that I need to populated both subcategory and brand drop down at once (when a category is selected).

It is working and both the drop downs are populated at once according to the category id being passed (it's the parameter of the above functions selected).

I'm unnecessarily using an alert box at the bottom of the function getBrandList(). When this alert box is commented, only one drop down which is subcategory is populated. Brands remain empty. I don't need this alert box anymore.

Why does this happen? What is the solution?

Upvotes: 4

Views: 1529

Answers (5)

teynon
teynon

Reputation: 8288

seriyPS's basically hit the target on this. The issue is in fact the xmlhttp variable. You need to declare it local within each function it is being used. Basically, create a closure for the function calls. The issue isn't necessarily that it needs to be "local" however, but it is being redefined in the second request as a result of being a global variable. This essentially kills the initial request because the variable now points to the second request.

The reason the alert box makes it work is because the first request is finishing the ajax request before you can "click" ok. (The alert box will pause the javascript execution and therefore delay the second request until after you have clicked ok.)

To fix this, you can modify your code to use a different variable for each request. Try changing your function to something like this:

// Global Variables
var brandListRequest;
var subcategoryRequest;

function ajax()
{
    var xmlhttp; //!!
    if(window.XMLHttpRequest)
    {
        xmlhttp=new XMLHttpRequest();
    }
    else
    {
        xmlhttp = new ActivexObject("Microsoft.XMLHTTP");
    }
    return xmlhttp; //!!
}

function getBrandList(selected)  //selected is the category id.
{               
    brandListRequest = ajax(); //!!
    brandListRequest.onreadystatechange=function()
    {
        if(brandListRequest.readyState==4 && brandListRequest.status==200)
        {
            document.getElementById("brandList").innerHTML=brandListRequest.responseText;            
        }
    }

    brandListRequest.open("GET","ajax/BrandAjax.php?selected="+selected, true);
    brandListRequest.send();     
    //alert(selected);            
}

function getSubcategoryList(selected) //selected is the category id.
{                       
    getBrandList(selected); //First above function is invoked to populate brands.
    subcategoryRequest = ajax(); //!!
    subcategoryRequest.onreadystatechange=function()
    {
        if(subcategoryRequest.readyState==4 && subcategoryRequest.status==200)
        {
            document.getElementById("subCategoryList").innerHTML=subcategoryRequest.responseText;                              
        }
    }

    subcategoryRequest.open("GET","ajax/SubCatAjax.php?selected="+selected, true);
    subcategoryRequest.send();             
}

Upvotes: 1

Priyank Doshi
Priyank Doshi

Reputation: 13151

I think you may use call back function . But i do suggest using jquery. Its a lot simpler. You dont need to do all there manually.( creating xhttprequest object and maintaining the state of response and all those clumsy activex object related things)

Upvotes: 1

codef0rmer
codef0rmer

Reputation: 10520

I would recommend you to use jQuery for that.

 1. Load the first dropdown with categories on page load
 2. Call the following ajax call on change event of the first dropdown, categoryList
    $('#categoryList').change(function () {
      $('#subCategoryList').load("ajax/SubCatAjax.php?selected="+this.value);
      $('#brandList').load("ajax/BrandAjax.php?selected="+$('#subCategoryList').val());
    });
 3. Call the following ajax call on change event of the second dropdown, subcategoryList.
    $('#subCategoryList').change(function () {
      $('#brandList').load("ajax/BrandAjax.php?selected="+this.value);
    });

P.S. I assume that your ajax requests return string containing options eg. <option value='1'>subcategory1</option><option value='2'>subcategory2</option> ..etc. and you want to load brands based on subcategory selected not the category selected.

Upvotes: 1

seriyPS
seriyPS

Reputation: 7102

First, just recommend you to try some modern JavaScript frameworks like JQuery for this.

How @tzerb say: you override global variable xmlhttp before first AJAX request finish. You must use local variables for this.

function ajax()
{
    var xmlhttp; //!!
    if(window.XMLHttpRequest)
    {
        xmlhttp=new XMLHttpRequest();
    }
    else
    {
        xmlhttp = new ActivexObject("Microsoft.XMLHTTP");
    }
    return xmlhttp; //!!
}

function getBrandList(selected)  //selected is the category id.
{               
    xmlhttp = ajax(); //!!
    xmlhttp.onreadystatechange=function()
    {
        if(xmlhttp.readyState==4 && xmlhttp.status==200)
        {
            document.getElementById("brandList").innerHTML=xmlhttp.responseText;            
        }
    }

    xmlhttp.open("GET","ajax/BrandAjax.php?selected="+selected, true);
    xmlhttp.send();     
    //alert(selected);            
}

function getSubcategoryList(selected) //selected is the category id.
{                       
    getBrandList(selected); //First above function is invoked to populate brands.
    xmlhttp = ajax(); //!!
    xmlhttp.onreadystatechange=function()
    {
        if(xmlhttp.readyState==4 && xmlhttp.status==200)
        {
            document.getElementById("subCategoryList").innerHTML=xmlhttp.responseText;                              
        }
    }

    xmlhttp.open("GET","ajax/SubCatAjax.php?selected="+selected, true);
    xmlhttp.send();             
}

With JQuery you code can look like:

function getBrandsList(selected){
    $("#brandList").load("ajax/BrandAjax.php?selected="+selected);
}
function getSubcategoryList(selected){
    $("#brandList").load("ajax/SubCatAjax.php?selected="+selected);
}

Upvotes: 2

tzerb
tzerb

Reputation: 1433

I think the second ajax() call is wiping out the xmlhttp variable. When you put your alert in, I bet it's giving the first call time to finish before starting the second. You should probably call ajax() earlier and remove the call from your handlers.

Upvotes: 2

Related Questions