使用流水线服务器端处理的DataTable在重绘时会丢弃本地更改吗?

时间:2018-01-11 12:06:01

标签: datatables

背景

我有一个带有一些小部件的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重新加载会起作用,因为后端本身现在反映了我刚刚改变行的状态,但我不想这样做。

如何将此本地更改提交到从服务器检索的数据?

1 个答案:

答案 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的缓存一样。