DataTable.Responsive.renderer.listHiddenNodes() BUG - responsive elements don't update on reload

DataTable.Responsive.renderer.listHiddenNodes() BUG - responsive elements don't update on reload

gracjan2024gracjan2024 Posts: 2Questions: 1Answers: 0

listHiddenNodes() is intended to move DOM objects and their events between columns to their corresponding responsive view state. This works as intended on a static table. However, once a DataTable.ajax.reload is called, the responsive elements do not update with the new data from the server. This is because the _childNodes function short circuits a check to see whether the element is cached, and if it is to return the cached element. This results in the responsive elements to show the original stale data, which renders the responsive view's elements static.

https://cdn.datatables.net/v/dt/dt-2.0.5/af-2.7.0/kt-2.12.0/r-3.0.2/datatables.js
lines 16406 - 16423

_childNodes: function (dt, row, col) {
    var name = row + '-' + col;

    if (this.s.childNodeStore[name]) {
      return this.s.childNodeStore[name];
    }

    // https://jsperf.com/childnodes-array-slice-vs-loop
    var nodes = [];
    var children = dt.cell(row, col).node().childNodes;
    for (var i = 0, ien = children.length; i < ien; i++) {
        nodes.push(children[i]);
    }

    this.s.childNodeStore[name] = nodes;

    return nodes;
},

removing if (this.s.childNodeStore[name]) { return this.s.childNodeStore[name]; } resolves this issue entirely.

    //if (this.s.childNodeStore[name]) {
    //  return this.s.childNodeStore[name];
    //}

It doesn't cause unintended side-effects to the operation of the datatable, as the cache is still present for _childNodesRestore. It will have a slight performance impact on large tables that are re-rendering responsive views, but that performance loss compared to not obtaining dynamic data during a reload command is not a worthwhile trade off.

Answers

  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    I'm not sure it is quite as simple as that. An entry in childNodeStore not only stores the elements, but also indicates that they have been moved. So if there are items in childNodeStore, but the function is allowed to continue to run, it will overwrite and loose the original elements. That might be okay in this case, but I'm not sure that it is in all.

    Can you link to a test case showing the issue so I can work more on this when I get a chance to do so please?

    Allan

  • gracjan2024gracjan2024 Posts: 2Questions: 1Answers: 0

    It's challenging to get a test case that can be posted that demonstrates the issue, because it only happens when the reload call pulls in new information to the table. I'll try to work up a sample endpoint that demonstrates the issue when I get home tonight.

    However, the childNodeStore starts with no elements. The original elements are still present in the table, they are simply hidden with "display:none", so subsequent _childNodes without the cache pulls valid elements (and in the case that the table was reloaded, the most recent element). I didn't see these function calls used in an instance where the table elements were actually removed from the DOM. The library is large, however, and maybe the api that deals with making columns visible/hidden dynamically relies on this cache. However, for the responsive table, what this cache does is once it's loaded it becomes the de-facto element for the responsive view despite the cell elements changing during a reload.

    Another way to fix the issue would be to clear the cache on the reload call. For my purposes, this was more complicated. I tried to use callbacks and other hooks in the API to clear the cache, I even tried writing a custom render function based on the original render function. Unfortunately, passing a custom function in doesn't gain access to "this" (Responsive class) and private members of the Responsive class, which inhibited my ability to recreate the nodes as the native listHiddenNodes() function call does. This may simply be a skill issue on my part, but I only have so much time. The only thing that worked was removing the short-circuit, and doing so didn't break the ability of the responsive table to render a tables while expanding and contracting the window's width.

    I'll get you a working sample so you can see it. I understand there may be other consequences that are beyond what I can see. However, I spent several hours working trough this, as for my use case it was a bug. As best I can tell the cache only provides a benefit in performance on subsequent calls but once loaded it's stuck on the original elements despite the DOM elements changing. Since the DOM elements are always there, the cache isn't strictly necessary. There are better ways to solve this edge case to preserve performance while maintaining intended functionality, but for me simply removing it made it work as intended.

Sign In or Register to comment.