看了一段时间DataTables.js的源码后,我得出的结论是没有办法以期望的方式挂钩过滤。有自定义过滤器的钩子,但它们只能用来隐藏东西,不能用来显示东西。
但是,有一个'filter'
事件在过滤之后但在表格呈现之前触发。我的解决方案为此事件安装了一个处理程序:
$('table#mydatatable').bind('filter', function() {
var nTable = $(this).dataTable();
var oSettings = nTable.fnSettings();
//collect the row IDs of all unsaved rows
var aiUnsavedRowIDs = $.grep(oSettings.aiDisplayMaster, function(iRowID) {
var oRowData = nTable.fnGetData(iRowID);
return is_unsaved(oRowData);
});
//prepare lookup table
var oUnsavedRecordIDs = {};
$.each(aiUnsavedRowIDs, function(idx, iRowID) {
oUnsavedRecordIDs[iRowID] = true;
});
//remove unsaved rows from display (to avoid duplicates after the
//following step)
for (var i = oSettings.aiDisplay.length; i >= 0; i--) {
//iterate backwards, because otherwise, removal from aiDisplay
//would mess up the iteration
if (oUnsavedRecordIDs[ oSettings.aiDisplay[i] ]) {
oSettings.aiDisplay.splice(i, 1);
}
}
//insert unsaved records at the top of the display
Array.prototype.unshift.apply(oSettings.aiDisplay, aiUnsavedRowIDs);
//NOTE: cannot just say oSettings.aiDisplay.unshift(aiUnsavedRowIDs)
//because this would add the array aiUnsavedRowIDs as an element to
//aiDisplay, not its contents.
});
这里会发生什么?首先,我通过浏览找到所有未保存的行oSettings.aiDisplayMaster
。此数组以正确的排序顺序引用此 DataTable 中的所有行。的元素aiDisplayMaster
是 DataTables 内部数据存储的整数索引(每行一个索引)。
过滤过程会遍历 中的行aiDisplayMaster
,并将所有匹配行的行 ID 放置在 中oSettings.aiDisplay
。此数组控制将呈现哪些行(在此事件处理程序完成之后!)。整个过程是这样的:
[1, ..., numRows]
|
| sorting
v
oSettings.aiDisplayMaster
|
| filtering
v
oSettings.aiDisplay
|
| rendering
v
DOM
因此,在找到所有未保存的记录之后aiDisplayMaster
(使用我is_unsaved()
为了这个片段而包装在一个函数中的自定义逻辑),我将它们全部添加到aiDisplay
(在删除这些行的现有实例之后,以避免重复)。
这种特定实现的副作用是所有未保存的行都出现在表的顶部,但在我的情况下,这实际上是可取的。