我有一个带有一些小部件的DataTable(实际上是带有点击处理程序的Font Awesome图标)rendered inside it来切换"状态"由表中的行表示的后端实体。
使用serverSide: true
功能填充表格,以便从后端(最终使用SQL LIMIT
)提取页面,而不是加载整个批次,然后在浏览器中对其进行分页。
我还使用" pipelining"以(小)块的形式从服务器获取页面,而不是一次一个地获取页面。
一些代码:
$(function() {
$('#myTable').DataTable({
columns: [
{ data: "id" },
{
data: "state",
render: function(data, type, row) {
if (type === 'display') {
if (data === true) {
return '<i title="On" data-id="' + row["id"] + '"'
+ ' class="fa fa-check-circle toggle_off" />';
}
else {
return '<i title="Off" data-id="' + row["id"] + '"'
+ ' class="fa fa-check toggle_on" />';
}
}
return data;
}
}
],
serverSide: true,
deferRender: true,
ordering: false,
searching: false,
pageLength: 25,
ajax: $.fn.dataTable.pipeline({
url: "/backend/getData"
})
});
// (We'll see what setState is in a moment)
$('.toggle_off').on('click', function() {
setState([this.dataset.id], false);
});
$('.toggle_on').on('click', function() {
setState([this.dataset.id], true);
});
});
后端返回这样的数据:
[
{"DT_RowId": 1, "id": 1, "state": true},
{"DT_RowId": 2, "id": 2, "state": false},
{"DT_RowId": 3, "id": 3, "state": false},
{"DT_RowId": 4, "id": 4, "state": true}
]
和HTML看起来像这样:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="font-awesome.min.css" />
<script type="text/javascript" src="datatables.js" />
</head>
<body>
<table id="myTable">
<thead>
<tr>
<th>ID</th>
<th>State</th>
</tr>
</thead>
<tbody />
</table>
</body>
</html>
(显然,如果没有可用的后端数据源,就无法使用实时测试用例。)
当我执行其中一个切换时,我不需要重新加载整个数据集/页面,因为我确切地知道受影响的行将如何变化。所以我做了以下事情:
/**
* Sets the state of one (or more!) entries, immediately reflecting
* those changes in the table if successful (without requiring a fresh
* backend table retrieval).
*/
function setState(row_ids, bool) {
var table = $('#myTable').DataTable();
var rows = table.rows(row_ids);
$.ajax({
dataType: "json",
method: "POST",
url: "/backend/setState",
data: { row_ids: row_ids }
})
.done(function(data) {
// Change successful; update table to match
rows.every(function() {
var d = this.data();
d["state"] = bool;
// Commit by invalidating DT's cache for this row
this.invalidate();
});
// Now redraw per docs
table.draw(false);
})
.fail(function(jqxhr, textStatus, error) {
alert("State change failed");
});
}
但是,我观察到虽然this.invalidate()
调用具有立即的图形效果,但它并不持久:更改为另一个页面并返回失去更改,并立即调用{{1} (每个文档)也将数据放回到从后端检索时所处的状态。
我想进行AJAX重新加载会起作用,因为后端本身现在反映了我刚刚改变行的状态,但我不想这样做。
如何将此本地更改提交到从服务器检索的数据?
答案 0 :(得分:0)
tl; dr:自然缓存。
你的服务器端渲染和流水线的混合略微与文档示例相混淆。
虽然.draw()
来电确实&#34;提交&#34;更改为DataTables自己的缓存后,您将忘记管道缓存,该缓存仍包含从后端检索的状态。也许不直观地,this.invalidate()
模式中的draw()
显然也会执行AJAX重新加载,但随后您将进入管道缓存并变为旧状态。
要解决此问题,您也可以使管道缓存无效:
serverSide
虽然这需要在下一个function setState(row_ids, bool) {
var table = $('#myTable').DataTable();
var rows = table.rows(row_ids);
$.ajax({
dataType: "json",
method: "POST",
url: "/backend/setState",
data: { row_ids: row_ids }
})
.done(function(data) {
// Change successful; update table to match
rows.every(function() {
var d = this.data();
d["state"] = bool;
// Commit by invalidating DT's cache for this row
this.invalidate();
});
// Don't redraw now, but clear pipeline cache otherwise
// our local changes will be lost the next time we do
// (unless there is a cache miss for some reason and the
// new state is pulled from the backend)
table.clearPipeline();
})
.fail(function(jqxhr, textStatus, error) {
alert("State change failed");
});
}
或下次更改页面时重新加载AJAX。另一种方法是扩展管道代码以允许直接修改其缓存,就像您已经对DataTables的缓存一样。