使用Ajax同时填充两个下拉框

4
我有三个 HTML DropDownList(下拉列表)()。第一个 DropDownList 包含类别,第二个包含不同产品的子类别,第三个包含品牌(或制造商)。
当选择一个类别时,根据传递给Ajax函数的类别ID,应该立即从数据库中填充两个下拉列表子类别和品牌。我正在使用以下Ajax代码。
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();             
}   

当选择一个类别时,会调用getSubcategoryList(selected) Javascript函数来进行Ajax请求。问题在于,我需要同时填充子类别和品牌下拉框(当选择一个类别时)。
它正在工作,根据传递的类别id(它是上述函数selected的参数)同时填充两个下拉框。
我不必要地在getBrandList()函数底部使用了一个警告框。当这个警告框被注释掉时,只有一个下拉框——子类别被填充,品牌保持为空。我不再需要这个警告框。
为什么会发生这种情况?有什么解决办法?
5个回答

2

我认为第二个ajax()调用正在清除xmlhttp变量。当您放置警报时,我打赌它会在开始第二个调用之前给第一个调用完成的时间。您应该在更早的时候调用ajax()并从处理程序中删除调用。


我同意这个观点。没有理由期望在子类别列表调用之前,获取品牌列表请求已经完成。警告框允许同步完成调用。你需要在这里强制同步,因为第二个调用依赖于第一个调用的结果。一般来说,我会使用回调函数来明确地在第一个调用返回后才进行第二个调用。 - jatrim
此外,我认为如果使用单个全局 XHMLHTTP 变量,任何打算异步进行的请求如果连续发出,也很可能会失败。 - jatrim

2

首先,建议您尝试一些现代的JavaScript框架,如JQuery。

@tzerb说:在第一个AJAX请求完成之前,您重写了全局变量xmlhttp。您必须使用本地变量来处理此问题。

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();             
}

使用 JQuery 编写的代码如下:

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

xmlhttp 设为本地变量不起作用。我尝试了这个方法(和你说的一样),还尝试了使用 jQuery,但仍然没有成功。 - Bhavesh

1

我认为您可以使用回调函数。但是我建议使用jQuery,它更简单。您不需要手动完成所有这些操作(创建xhttprequest对象并维护响应状态以及所有那些笨拙的activex对象相关的事情)。


1
我建议您使用jQuery
 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);
    });

附言:我假设您的ajax请求返回包含选项字符串,例如<option value='1'>子类别1</option><option value='2'>子类别2</option>等,并且您想根据所选子类别加载品牌,而不是所选类别。


我尝试了一下,但不得不悲伤地说它产生了相同的问题。 - Bhavesh

1

seriyPS的回答基本上命中了要害。问题实际上在于xmlhttp变量。您需要在每个使用它的函数内部声明它为局部变量。基本上,为函数调用创建一个闭包。问题不一定是需要“局部”变量,而是由于它是全局变量,在第二个请求中被重新定义。这实际上会使初始请求失败,因为变量现在指向第二个请求。

警告框能够使其工作的原因是因为第一个请求在您单击“确定”之前完成了ajax请求。(警告框将暂停javascript执行,因此延迟第二个请求直到您单击“确定”后才会继续。)

要解决此问题,您可以修改代码以使用每个请求的不同变量。尝试将您的函数更改为以下内容:

// 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();             
}

成功完成。这可能很简单,但我想不出来。非常感谢您的时间。学到了新东西。 - Bhavesh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接