【问题标题】:Automatically canceling jqGrid request自动取消 jqGrid 请求
【发布时间】:2013-02-14 18:39:50
【问题描述】:

我认为该用户提出了与我相同的问题,但提出问题的原因不同,因此他接受了不同的解决方案。我需要做他最初要求的事情:

Automatically cancelling jqgrid request

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

这是我迄今为止尝试过的:

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

【问题讨论】:

    标签: javascript ajax jqgrid xmlhttprequest


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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 嗨@Aternus,我使用的是jqgrid 4.3.1版本,我检查了4.3.1 jqgrid不支持事件触发器处理程序,我们可以使用其他选项
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-19
      • 2012-01-18
      • 1970-01-01
      • 2015-10-06
      • 1970-01-01
      相关资源
      最近更新 更多