问题 jquery ui autocomplete:如何在文本输入失去焦点后取消缓慢的ajax请求


我正在使用一个与ajax查找绑定的JQuery UI自动完成字段,有时可能会相当慢。有时,用户将远离文本输入字段  ajax查询启动但是 之前 ajax调用返回。发生这种情况时,即使文本输入不再具有焦点,也会显示自动完成弹出窗口,并且解除弹出窗口的唯一方法是选择一个项目(而不是标记到另一个字段)。

实际上,这个 jquery ui demo 表现出相同的行为(例如,在文本字段中输入'ariz',等待'搜索'动画出现,然后在返回任何结果之前跳出字段。)

一个有效的解决方案(但感觉就像一个黑客)是检查ajax的成功回调,看看文本字段是否仍然具有焦点,如果不是用空列表调用response(),例如:

        $( "#city" ).autocomplete({
        var elem = this.element;
        source: function( request, response ) {
            $.ajax({
                url: "http://ws.geonames.org/searchJSON",
                data: {name_startsWith: request.term},
                success: function( data ) {
                    if(!$(elem).is(':focus') {
                        response({});
                        return;
                    }
                    response( $.map( data.geonames, function( item ) {
                        return {
                            label: item.name + (item.adminName1 ? ", " + item.adminName1 : "") + ", " + item.countryName,
                            value: item.name
                        }
                    }));
                }
            });
        }
    });

有更优雅的解决方案吗?理想情况下,一旦用户选中文本输入字段,我就想取消ajax请求。


10449
2017-10-13 01:51


起源



答案:


$.ajax 返回一个 jqXHR 对象和该对象暴露了 abort 方法 潜在的 XMLHttpRequest 目的。所以,你只需要藏匿 jqXHR 并在合适的时间中止请求。也许这样的事情:

source: function(request, response) {
    var $this = $(this);
    var $element = $(this.element);
    var jqXHR = $element.data('jqXHR');
    if(jqXHR)
        jqXHR.abort();
    $element.data('jqXHR', $.ajax({
        // ...
        complete: function() {
            // This callback is called when the request completes
            // regardless of success or failure.
            $this.removeData('jqXHR');
            // And dismiss the search animation.
            response({});
        }
    });
}

然后你会想要一些东西 #city

$('#city').blur(function() {
    var $this = $(this);
    var jqXHR = $(this).data('jqXHR');
    if(jqXHR)
        jqXHR.abort();
    $this.removeData('jqXHR');
});

在自动完成程序的正常操作期间,有时会出现短暂的模糊/焦点,但这只会在有人从列表中选择某些内容时发生;不应该有 $.ajax 当发生这种情况时请求运行,所以我们不需要担心它。如果我错了,那么你可以通过在里面使用一个计时器来克服它 blur 处理程序和取消计时器 focus 回调(您可以将计时器ID存储在另一个中 .data() 插槽也是)。

我没有测试过这个,但我很确定它会起作用。


14
2017-10-13 02:27



这很棒!它让我95%,只有几个问题:1)在源匿名函数中,'this'是自动完成对象,而不是元素 - 使用'this.element'。一旦我这样做了数据绑定工作。 2)在完整的anon函数中,添加一个“response({})”来解除搜索动画。除此之外,这是完美的。非常感谢! - NobodyMan
fyi:我在你的回答中添加了“编辑”,但我没有编辑权限。我不确定您是否可以接受编辑或“同行评审员需要”。否则,一旦进行此编辑,我可以将此答案标记为正确。 - NobodyMan
@NobodyMan:对不起,我刚刚把它写在了我的头顶。我不得不稍微调整你的编辑以使其立即获得批准(否则我们必须等待两个人批准它)所以我移动了评论。 - mu is too short
太好了,谢谢! - NobodyMan
@NobodyMan:谢谢你提出一个有趣的问题。 - mu is too short


答案:


$.ajax 返回一个 jqXHR 对象和该对象暴露了 abort 方法 潜在的 XMLHttpRequest 目的。所以,你只需要藏匿 jqXHR 并在合适的时间中止请求。也许这样的事情:

source: function(request, response) {
    var $this = $(this);
    var $element = $(this.element);
    var jqXHR = $element.data('jqXHR');
    if(jqXHR)
        jqXHR.abort();
    $element.data('jqXHR', $.ajax({
        // ...
        complete: function() {
            // This callback is called when the request completes
            // regardless of success or failure.
            $this.removeData('jqXHR');
            // And dismiss the search animation.
            response({});
        }
    });
}

然后你会想要一些东西 #city

$('#city').blur(function() {
    var $this = $(this);
    var jqXHR = $(this).data('jqXHR');
    if(jqXHR)
        jqXHR.abort();
    $this.removeData('jqXHR');
});

在自动完成程序的正常操作期间,有时会出现短暂的模糊/焦点,但这只会在有人从列表中选择某些内容时发生;不应该有 $.ajax 当发生这种情况时请求运行,所以我们不需要担心它。如果我错了,那么你可以通过在里面使用一个计时器来克服它 blur 处理程序和取消计时器 focus 回调(您可以将计时器ID存储在另一个中 .data() 插槽也是)。

我没有测试过这个,但我很确定它会起作用。


14
2017-10-13 02:27



这很棒!它让我95%,只有几个问题:1)在源匿名函数中,'this'是自动完成对象,而不是元素 - 使用'this.element'。一旦我这样做了数据绑定工作。 2)在完整的anon函数中,添加一个“response({})”来解除搜索动画。除此之外,这是完美的。非常感谢! - NobodyMan
fyi:我在你的回答中添加了“编辑”,但我没有编辑权限。我不确定您是否可以接受编辑或“同行评审员需要”。否则,一旦进行此编辑,我可以将此答案标记为正确。 - NobodyMan
@NobodyMan:对不起,我刚刚把它写在了我的头顶。我不得不稍微调整你的编辑以使其立即获得批准(否则我们必须等待两个人批准它)所以我移动了评论。 - mu is too short
太好了,谢谢! - NobodyMan
@NobodyMan:谢谢你提出一个有趣的问题。 - mu is too short