free-jqGrid 外部过滤与 Grid 的 beforeRequest() 或 onPaging() 事件一起使用

free-jqGrid External Filtering Used With Grid's beforeRequest() or onPaging() Event

使用免费的 jqGrid(版本 4.15.6)显示有关发票的非常基本的信息(即:创建日期、到期日期、客户、总计、状态)。发票网格只显示了几个相关的列,因为不需要显示更多。实际上,还有许多其他与发票相关的字段未显示。我想为最终用户提供基于许多其他参数过滤网格的能力,这些参数根本不是网格内容的一部分。

我知道 jqGrid 提供内置搜索,您可以轻松地添加包含所有数据的隐藏列,但我觉得这对我们不利——发票包含大量数据——数据不是必然只存在于发票数据库中 table。我们希望网格在基本发票数据之外提供许多其他筛选选项,但我们不想使用内置筛选选项。相反,我想使用一个单独的 HTML table 和一堆搜索字段,我们的服务器端代码知道如何撤回)。当决定调用外部过滤器时,我们希望网格加载与该组合过滤器匹配的所有发票。如果选择使用网格的分页按钮进行导航,我们希望网格继续使用原始的外部过滤参数。

希望这是有道理的。也许我只是想得太多了,但我相当确定网格被设计为使用它内置在 filtering/searching tools/dialog 中,而且我还没有找到覆盖此行为的方法。实际上,我使用的是较旧的 jqGrid,但涉及使用 jQuery 将默认寻呼机完全替换为自定义 HTML 和事件处理。我永远无法用旧的 jqGrid 解决这个问题,所以我选择自己编写。但是那个代码不是最佳的,甚至我知道它受到了很多批评。升级到 4.15.6 后,我想以最好的方式做到这一点,我想保持它的逻辑性和实用性。

我曾尝试使用 beforeRequest() 和 onPaging() 事件来更改 'url' 参数,认为如果我修改 url,我可以更改 GET 以包含我们所有的自定义过滤字段。似乎不起作用,因为 url 永远不会改变最初定义的值。控制台日志记录确实显示事件触发,但 url 没有变化。最重要的是,网格始终将其自己的页面字段、_search 字段等传递给服务器,因此服务器永远不会看到过滤请求。

如何定义自己的自定义过滤与分页加载程序,并仍然利用内置的分页事件?我错过了什么?

**** 添加到与原始问题无关的问题的已删除代码 *********

很难回答您的问题,因为您没有发布显示您如何使用 jqGrid 的代码片段,而且还不知道可能需要在所有页面中显示的数据总数。

通常有两种主要的自定义过滤实施方案:

  • 服务器端过滤
  • 客户端过滤

还可以混合使用两种过滤方式。例如,可以根据一些固定的过滤器(特定用户的所有发票或一个组织的所有发票,上个月的所有发票)从服务器加载所有发票,然后使用 loadonce: true, forceClientSorting: true 选项进行排序和过滤客户端返回的数据。用户还可以使用搜索对话框的过滤器工具栏在本地过滤数据子集。

客户端的性能在去年有了本质上的提高,并且可以非常快速地从服务器加载相对较大的 JSON 数据。因此,严格建议使用客户端过滤。为了更好地理解本地排序、过滤和分页的性能,我建议您尝试 the demo 上的功能。你会看到本地过滤 5000 行和 13 列的网格的时间更好,因为你可以预期主要是从到服务器的往返以及在一些组织良好的数据库上处理服务器端过滤。这就是为什么我建议考虑尽可能使用客户端排序(或 loadonce: true, forceClientSorting: true 选项)的原因。

如果您需要在服务器上过滤数据,那么您只需在每次请求时向服务器发送额外的参数。可以通过在 postData 中包含额外的参数来做到这一点。有关更多详细信息,请参阅 the old answer。或者可以使用 serializeGridData 到 extend/modify 数据,这将被设置到服务器。

从服务器加载数据后,可以在本地进行排序和筛选,然后第一页数据将显示在网格中。要强制进行本地过滤,只需将 forceClientSorting: true 添加到众所周知的 loadonce: true 参数即可。它强制对从服务器返回的数据应用 local 逻辑。因此,可以使用 postData.filterssearch: true 强制进行额外的本地过滤,并使用 sortnamesortorder 参数强制进行本地排序。

关于使用隐藏列的另一个重要说明。每个隐藏列都将强制创建 DOM 个元素,这些元素表示不需要的 <td> 个元素。您在页面上放置的 DOM 元素越多,页面就越慢。如果将使用本地数据(或者如果使用 loadonce: true),那么 jqGrid 会将与每一行关联的数据保存两次:一次作为 JavaScript 对象,一次作为网格中的单元格(<td> 元素) .免费的 jqGrid 允许使用 "additional properties" 而不是隐藏列。如果没有数据将放置在网格的 DOM 中,但数据将保存在 JavaScript 对象中,并且 能够以相同的方式按其他属性排序或过滤与其他列一样。以最简单的方式,可以删除所有隐藏列并添加 additionalProperties 参数,该参数应该是带有附加属性名称的字符串数组。 additionalProperties 的字符串元素可以是具有与 colModel 相同结构的对象。例如,additionalProperties: [{ name: "taskId", sorttype: "integer"}, "isFinal"]。请参阅 the demo as an example. The input data of the grid can be seen here. Another demo 显示搜索对话框包含除 jqGrid 列之外的其他属性。 searching 的注释部分 columns 显示了更高级的方法来指定列表和列的顺序以及搜索对话框中显示的其他属性。

请原谅我这样回答,但这个问题是从一个与过滤和分页相关但使用外部过滤源的主题开始的。 Oleg 实际上有几个关于许多线程的演示,我可以使用它们来完成自定义过滤并维护默认的内置分页。所以他的回答将是原问题主题的公认答案。

但是在原来的解决方案中,我遇到了另一个初始加载网格的问题。如果没有其他过滤器已经到位,我想让网格加载具有默认过滤值。这真的应该是一个不同的问题,因为它真的没有影响第一个。

我发现了另一个关于完全不同问题的 Oleg 回复:

jqGrid - how to set grid to NOT load any data initially?

Oleg 回答了那个问题,那个答案解决了我们的第二个需要以一种方式加载,然后允许另一种方式。

因此,在初始加载时,我们在服务器端寻找过滤器参数。 None给定了吗?我们使用默认过滤来提取记录。参数存在?我们使用初始提供的参数。与初始加载的不同之处在于我们不 AJAX 退出。我们改为 json_encode 数据并将其放置在网格定义中,如下所示:

$('#grd_invoices').jqGrid(
...
url: '{$modulelink}&sm=130',
data: {$json_encoded_griddata},
datatype: 'local',
...
});

由于数据类型设置为'local',网格最初不会去服务器,所以数据参数被网格使用。一旦我们准备好过滤,我们就使用另一个问题的另一个答案中的 Oleg 解决方案来动态应用过滤器,如下所示:

var myfilter = { groupOp: 'AND', rules: []};
myfilter.rules.push({field:'fuserid',op:'eq',data:$('#fuserid').val()});
myfilter.rules.push({field:'finvoicenum',op:'eq',data:$('#finvoicenum').val()});
myfilter.rules.push({field:'fdatefield',op:'eq',data:$('#fdatefield').val()});
myfilter.rules.push({field:'fsdate',op:'eq',data:$('#fsdate').val()});
myfilter.rules.push({field:'fedate',op:'eq',data:$('#fedate').val()});
myfilter.rules.push({field:'fwithin',op:'eq',data:$('#fwithin').val()});
myfilter.rules.push({field:'fnotes',op:'eq',data:$('#fnotes').val()});
myfilter.rules.push({field:'fdescription',op:'eq',data:$('#fdescription').val()});
myfilter.rules.push({field:'fpaymentmethod',op:'eq',data:$('#fpaymentmethod').val()});
myfilter.rules.push({field:'fstatus',op:'eq',data:$('#fstatus').val()});
myfilter.rules.push({field:'ftotalfrom',op:'eq',data:$('#ftotalfrom').val()});
myfilter.rules.push({field:'ftotal',op:'eq',data:$('#ftotal').val()});
myfilter.rules.push({field:'fmake',op:'eq',data:$('#fmake').val()});
myfilter.rules.push({field:'fmodel',op:'eq',data:$('#fmodel').val()});
myfilter.rules.push({field:'fserial',op:'eq',data:$('#fserial').val()});
myfilter.rules.push({field:'fitemid',op:'eq',data:$('#fitemid').val()});
myfilter.rules.push({field:'ftaxid',op:'eq',data:$('#ftaxid').val()});
myfilter.rules.push({field:'fsalesrepid',op:'eq',data:$('#fsalesrepid').val()});

var grid = $('#grd_invoices');
grid[0].p.search = myfilter.rules.length>0;
$.extend(grid[0].p.postData,{filters:JSON.stringify(myfilter)});
$('#grd_invoices').jqGrid('setGridParam',{datatype:'json'}).trigger('reloadGrid',[{page:1}]);

这允许我们让网格显示本地加载的初始数据,然后后续过滤将网格数据类型更改为 'json',这迫使网格使用新的过滤器参数转到服务器,在那里它加载更多特定过滤。

归功于 Oleg,因为我从许多问题中使用了他的许多帖子来得出最终结果。谢谢@Oleg!