【问题标题】:jquery ui autocomplete: how to cancel slow ajax request after text input loses focusjquery ui自动完成:文本输入失去焦点后如何取消慢速ajax请求
【发布时间】:2011-12-06 14:35:10
【问题描述】:

我正在使用一个 JQuery UI 自动完成字段,该字段与有时可能相当慢的 ajax 查找相关联。有时,用户会在 之后 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 请求。

【问题讨论】:

    标签: ajax jquery-ui jquery autocomplete


    【解决方案1】:

    $.ajax 返回一个jqXHR 对象,并且该对象公开了底层XMLHttpRequest 对象的abort method。因此,您只需要隐藏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() 插槽中)。

    我没有对此进行测试,但我很确定它会起作用。

    【讨论】:

    • 这太棒了!它让我达到了 95%,只有几个问题:1)在源匿名函数中,“this”是自动完成对象,而不是元素——使用“this.element”。一旦我这样做了,数据绑定就起作用了。 2)在完整的匿名函数中,添加“response({})”来关闭搜索动画。除此之外,这是完美的。非常感谢!
    • 仅供参考:我在您的答案中添加了“编辑”,但我没有编辑权限。我不确定您是否可以接受编辑或“同行评审员需要”。否则,一旦进行此编辑,我就可以将此答案标记为正确。
    • @NobodyMan:对不起,我只是把它写在我的脑海里。我不得不稍微调整一下您的编辑以使其立即获得批准(否则我们必须等待两个人批准它)所以我移动了评论。
    • @NobodyMan:感谢您提出一个有趣的问题。
    • 一张小纸条。您触发响应({});无论如何,它实际上折叠了我加载的自动建议项目。所以我修改了完整的complete: function(jqXHR, textStatus) { // This callback is called when the request completes // regardless of success or failure. $this.removeData('jqXHR'); // And dismiss the search animation. if ('success' != textStatus && 'notmodified' != textStatus) { response({}); } }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-31
    • 1970-01-01
    相关资源
    最近更新 更多