自动取消jqGrid请求

时间:2013-02-14 18:39:51

标签: javascript ajax jqgrid xmlhttprequest

我认为这个用户问我要问的同一个问题,但推动他的问题的原因是不同的,所以他接受了一个不同的解决方案。我需要做他最初要求的事情:

Automatically cancelling jqgrid request

我的jqGrid有一个搜索工具栏(输入字段显示在列标题下方但在数据上方)。大多数列都有下拉列表(stype = select),列出该列的可用过滤器选项,顶部有“全部”选项。使用填充我的jqGrid的JSON数据响应的服务器端代码很复杂,因此有点慢,特别是当过滤条件没有太多时。这意味着如果用户选择“全部”,则可能需要几秒钟才能显示任何结果。这本身很好,但是如果用户在响应返回之前选择了另一个过滤器,则网格不会取消现有请求,也不会提交新请求,所以在某些时候之后用户进行第二次选择,网格更新以显示第一个选择的响应。此外,当您更改过滤器选择时,网格会自动更新,因此要让它显示您想要的数据,您必须将您的选择更改为其他内容,等待加载,然后再加载改回来。

这是我到目前为止所尝试的内容:

$(document).ready(setupGrid);

var currentGridRequest;

function setupGrid() {
    var grid = $("#grid").jqGrid({
        ...
        loadError: function(xhr, status, error) {
            currentGridRequest = undefined;
        },
        loadComplete: function(data) {
            currentGridRequest = undefined;
        },
        loadBeforeSend: function(xhr, settings) {
            if (currentGridRequest !== undefined) {
                currentGridRequest.abort();
            }
            currentGridRequest = xhr;
        }
    });
}

我遇到的问题是,如果已经有飞行中的请求,则loadBeforeSend事件实际上不会触发。我已经尝试了事件文档页面(http://www.trirand.com/jqgridwiki/doku.php?id=wiki:events)中的其他事件:beforeRequest和jqGridToolbarBeforeSearch都表现出相同的行为。

我可以做什么来中止正在进行的请求并根据用户的最新选择继续搜索?这是jqGrid中的错误吗?我最初在版本4.2上遇到过这个问题;我刚刚升级到4.4.4而没有改变这种行为。

查看jqGrid代码,我看到的行为在不更改jqGrid代码本身的情况下似乎是不可避免的。 jqGrid在每个请求的开头设置一个标志(ts.grid.hDiv.loading)并在结尾处清除它;设置此标志后,将不会提交新的过滤条件,也不会触发任何事件。

我还考虑修改我的JSON响应,使其包含请求标准,然后编写一些JS代码来比较当前条件选择的响应。如果它们不匹配,我将忽略响应而不将其呈现给网格。由于jqGrid甚至没有提交第二组标准,因此该选项不在桌面上(即使我可以解决该问题,我目前的方法似乎更合适)。

2 个答案:

答案 0 :(得分:1)

我找到了一种方法来做我想做的事。我在几个地方使用jqGrid(在少数情况下在同一页面上包括多个网格),所以我把它分解成一个我可以从任何地方调用的函数,它包含自己的范围来管理是否有当前请求;只需传递一个网格,它将附加所有必要的事件处理程序。请注意,这将覆盖您为相关事件定义的任何现有处理程序。

function applyJqgridHandlers(grid) {
    (function(self, undefined) {
        var currentRequest;
        function abortCurrentRequestIfAny() {
            if (currentRequest !== undefined) {
                currentRequest.abort();
            }
        }
        self.clearCurrentRequest = function() {
            abortCurrentRequestIfAny();
            currentRequest = undefined;
        };
        self.setCurrentRequest = function(xhr) {
            abortCurrentRequestIfAny();
            currentRequest = xhr;
        };
    })(grid.currentRequestHolder = {});

    grid.currentRequestHolder.clearCurrentRequest();
    grid.jqGrid('setGridParam', {
        loadError: function(xhr, status, error) {
            grid.currentRequestHolder.clearCurrentRequest();
        },
        loadBeforeSend: function(xhr, settings) {
            grid.currentRequestHolder.setCurrentRequest(xhr);
        },
        loadComplete: function(data) {
            grid.currentRequestHolder.clearCurrentRequest();
        }
    });
    grid.bind('jqGridToolbarBeforeSearch', function() {
        grid.currentRequestHolder.clearCurrentRequest();
        this.grid.hDiv.loading = false;
    });
};

然后我只是从setupGrid()的末尾添加对此函数的调用。

此代码显式清除ts.grid.hDiv.loading标志,该标志不是已发布的jqGrid API的一部分,因此我认为此解决方案相当脆弱;无法保证它将继续适用于未来版本的jqGrid。如果有人对更好(不太脆弱)的方法有任何建议来解决这个问题,我会全力以赴。 :)

答案 1 :(得分:0)

@JakeRobb谢谢你的想法!我冒昧地创建了一个可以普遍使用而不会禁用原始jqGrid的任何功能的函数。

在jqGrid版本5.2.1上测试

jqGrid快速搜索

如果用户应用了新过滤器,

a.k.a会自动取消旧请求。

/**
 * Add the ability to rapidly search using the jqGrid Toolbar
 *
 * @param jqGridInstance string|object
 *
 * @author Kiril Reznik
 */
var jqGridRapidSearch = function(jqGridInstance) {
    var currentRequest = null,
        abortRequest = function() {
            if (currentRequest !== null) {
                currentRequest.abort();
            }
        },
        setRequest = function(xhr) {
            abortRequest();
            currentRequest = xhr;
        },
        clearRequest = function() {
            abortRequest();
            currentRequest = null;
        },
        $jqGrid = null;
    if ($.type(jqGridInstance) === 'string') {
        $jqGrid = $(jqGridInstance);
    } else if ($.type(jqGridInstance) === 'object' && $.type(jqGridInstance.jquery) === 'string') {
        $jqGrid = jqGridInstance;
    } else {
        throw 'jqGridRapidSearch requires a valid jqGrid instance parameter: Grid ID string or jQuery object.';
    }
    $jqGrid.on('jqGridLoadBeforeSend', function(e, xhr, settings) {
        setRequest(xhr);
    });
    $jqGrid.on('jqGridLoadComplete', function(e, data) {
        clearRequest();
    });
    $jqGrid.on('jqGridLoadError', function(e, xhr, status, error) {
        clearRequest();
    });
    $jqGrid.on('jqGridToolbarBeforeSearch', function(e) {
        clearRequest();
    });
};