jQuery - 有没有办法推迟从已经绑定的插件运行函数

时间:2013-03-13 21:22:44

标签: jquery select deferred

我们编写了一个通用的jQuery操作,该操作绑定到一个选择的国家/地区列表。它必然会选择国家;当它被改变时,调用服务器来获取状态......

$('#' + countryElementID).change(function () {
    var countryID = $('#' + countryElementID).val();
    $.ajax({
        type: 'POST',
        url: '/App/GetStatesByCountry',
        data: {
            id: countryID
        },
        dataType: 'json',
        success: function (result) {
            // build HTML replace via .html
        },
        failure: function (result) {
            // ...
        }
    });
});

以下是触发此操作的代码......

var populateCompanyInfo = function (resultData) {

var populateList = {
    CompanyName: 'input',
    Address1: 'input',
    Address2: 'input',
    City: 'input',
    Zip: 'input',
    Email: 'input',
    Phone: 'input',
    Fax: 'input',
    CountryID: 'select',
    StateID: 'select',
    Active: 'toggle'
}

$.each(populateList, function (name, value) {
    var a = eval('resultData.' + name);
    var sectionID = 'RealtyCompany';
    if (a != null || a != '') {
        if (value == 'input') {
            // ...
        }
        if (value == 'select') {
                var a = eval('resultData.' + name);
                $('#select' + sectionID + name).val(a);
                $('#select' + sectionID + name).trigger('change');
        }
        if (value == 'toggle') {
            // ...
        }
    }
});

我遇到的问题是它在填充状态之前选择StateID(从更改国家/地区下拉列表触发)。

我是否可以在Country下拉列表的泛型操作中传递一个变量,该变量基本上会等到变量传递完毕?我试着想办法在jQuery中加入一个延迟的动作,但是我很难找到一种方法来做到这一点。

1 个答案:

答案 0 :(得分:0)

看了这个小时后,一分钱掉了 - 这就是我认为我已经渗透了这个问题。我是否有书面的工作答案还有待观察。

无论你采用哪种方式,关键是让jqXHR'承诺'(通过AJAX获取所选国家的状态)可用于其他范围。我选择通过设置强加在国家/地区选择元素上的jQuery .data('fetchData')对象的属性来执行此操作。

然后,由于.each(populateList, ...)循环的工作方式(我还没有尝试改变它),jqXHR也需要作为循环内两个分支之间的外部成员传递。可以采用其他方法,但我发现的所有方法至少都是混乱的。

由于不保证.data()对象存在,因此需要相当大的安全性来增加脚本的批量。很可能有一种更简单的方法可以用更少的代码实现同样的目的。

以下是代码:

$(function() {
    var countryElementID = 'selectRealtyCompanyCountryID';
    $('#' + countryElementID).change(function () {
        var $this = $(this);
        var jqXHR = $.ajax({
            type: 'POST',
            url: '/App/GetStatesByCountry',
            data: { id: $this.val() },
            dataType: 'json',
            success: function (result) {
                // Build HTML replace via .html()
            },
            failure: function (result) {
                // Generic error handler
                alert('Generic error handler');
            }
        });
        var fetchData = $this.data('fetchStates');// May of may not exist.
        if(fetchData) fetchData.jqXHR = jqXHR;//Make the jqXHR available to other scopes via the DOM.
    });

    var populateCompanyInfo = function (resultData) {
        var populateList = {
            CompanyName: 'input',
            Address1: 'input',
            Address2: 'input',
            City: 'input',
            Zip: 'input',
            Email: 'input',
            Phone: 'input',
            Fax: 'input',
            CountryID: 'select',
            StateID: 'select',
            Active: 'toggle'
        }
        var fetchPromise = null;

        $.each(populateList, function (name, value) {
            var a = resultData[name];
            var sectionID = 'RealtyCompany';
            if(a) {
                if (value == 'input') {
                    // ...
                }
                if (value == 'select' && name == 'CountryID') {
                    //Branch for the CountryID select menu
                    var $el = $('#select' + sectionID + name);
                    var fetchData = $el.data('fetchStates');
                    if(!fetchData) {
                        $el.data('fetchStates', {});
                    }
                    if(fetchData.jqXHR && fetchData.jqXHR.abort) {//safety
                        fetchData.jqXHR.abort();//Kill any outstanding ajax requests of the same type.
                    }
                    $el.val(a).trigger('change');
                    fetchPromise = data.jqXHR;//Make the new jqXHR object available to the 'StateID' branch next time round the .each loop.
                }
                if (value == 'select' && name == 'StateID') {
                    //Branch for the StateID select menu
                    if(fetchPromise && fetchPromise.done) {//May of may not be defined.
                        fetchPromise.done(function(data, textStatus, jqXHR) {
                            // At this point the States element is freshly populated with states.
                            // Here, do whatever is necessary once the States element
                            // eg. set its .val() then trigger its 'change' event.
                        }).fail(function(jqXHR, textStatus, errorThrown) {
                            // Display error message?
                            // Set the States element to a default value?
                            alert('Specific error handler');
                        });
                    }
                }
                if (value == 'toggle') {
                    //...
                }
            }
        });
    }
});

经过测试以消除语法错误 - 仅此而已

修改

是的,它可以简化 - here's some better code。您将看到由于ajax失败而导致的错误消息 - 我还没有完全模拟获取状态。但错误信息很好 - 它们意味着事件的顺序是正确的。