invalidate('dom') throws exception for cells/rows which are not visible
invalidate('dom') throws exception for cells/rows which are not visible
Description of problem:
In recent versions of datatables, when calling invalidate('dom')
on cells or rows, if these rows / cells are not visible (they don't have a dom representation), an exception will be raised.
The exception is located in the _fnGetRowElements
, around this block of code :
// Existing row object passed in
tds = row.anCells;
for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
cellProcess( tds[j] );
}
For these specific rows, tds
is null
.
Test case
See the attached file for a test case : clicking the button will try to invalidate all rows, but only some of them are visible due to pagination. So, the invalidate function will perform an iteration until it reaches the first non visible row, triggering the exception.
Expected behaviour
This should probably be ignored silently. In my use case, I use ignore('dom')
to perform real-time updates on the datatable, not knowing if the cell/row is currently shown or not. Maybe it is easy to fix by just handling the cases when things are null (by skipping the processing), in _fnGetRowElements
and _fnInvalidate
?
Cheers,
Ben
This question has an accepted answers - jump to answer
Answers
Interesting one. To some degree, this error is not a bad thing, because
invalidate('dom')
is telling DataTables to read the data from the DOM elements. But if they haven't been created, then it can't - so I think the error might actually be correct.Perhaps it should not invalidate rows where the cells haven't been created yet, but then I'm not sure that would be obvious to the developer using DataTables, and the intention wouldn't be carried out.
Perhaps what you need to do is disable the defer render option (
deferRender
) so that the DOM nodes are present when you want them.Another would be to use
rows().nodes()
to then create a selector based on row nodes, so you wouldn't be attempting to update from the document when the cells aren't present.How are you doing the updates at the moment - are you writing to individual cells and then blanket calling invalidate on all rows? You coul do it on the specific cells that are being updated which would be more efficent.
Allan
The use case is similar to the ones I posted a long time ago in this thread.
There's a column with a custom widget, defined with
data: null
, that has a custom renderer. If I quote my own example, it looks like this :And row callbacks :
To reload data for these specific columns, I used to use invalidate('dom'), but after looking closer, I'm not sure if it's relevant. Maybe calling invalidate('data') is a sufficient and a better approach to get the cells updated ?
invalidate('dom')
tells DataTables to read the data for the row from the document. But if you update the table using an API method such asrow().data()
, then you don't need to invalidate the route - DataTables will do it for you.If you are getting new JSON data to display, that's how I would suggest you do it.
Allan
Thanks, Allan, this really helps a lot ! After a bit of struggle, I reimplemented my column differently using a function for data, instead of using a render callback :
Now I can invalidate a single cell, and trigger a single redraw using :
It seems to work very well.
However, I noticed that triggering that kind of updates in the early life of the table may result in a wrong class affectation in the DOM for some cells regarding sorting (they should all be tagged as 'dt-type-numeric sorting_1' but some of them might received only 'sorting_1' when playing with pagination. Is there something I'm doing wrong ?
Here's a fiddle illustrating this :
https://jsfiddle.net/efrgxdt1/1/
The first rows are randomly changed with a timer, simply clicking on page 2 will show that some cells don't get the 'dt-type-numeric' class.