1

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

自动取消 jqgrid 请求

我的 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 甚至没有提交第二组标准,因此该选项不在讨论范围内(即使我可以解决该问题,我目前的方法似乎更可取)。

4

2 回答 2

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 的未来版本。如果有人对解决此问题的更好(不那么脆弱)方法有任何建议,我会全力以赴。:)

于 2013-02-15T22:02:15.833 回答
1

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

在 jqGrid 版本 5.2.1 上测试

jqGrid 快速搜索

如果用户应用了新的过滤器,也就是自动取消旧的请求。

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

于 2017-10-15T12:05:47.933 回答