Reloading externally updated DOM data
Reloading externally updated DOM data
https://jsfiddle.net/wt627fL0/1/
I'm trying to integrate DataTables into an htmx website.
The table data is initially loaded from DOM. When deleting or updating a row in the table, htmx replaces the row with a new tr element returned from the server, but I can't refresh the Datatable with the new DOM.
When debugging, I can see that the tr is being replaced properly, but then I want to invalidate the Datatable, reload the data from DOM and re-draw Datatable to get the css classes for select feature added.
I've tried a few combinations of invalidate and draw:
1. DataTable().rows().invalidate('dom').draw();
, leads to the data being reverted back to the previous state, overwriting what htmx just fetched from the server
2. DataTable().rows().draw();
, same thing
3. otherwise, if I just DataTable().rows().invalidate('dom')
or do nothing, the DataTables select classes are not applied, and I can no longer click to select the row.
As I understand, whole idea with ``ìnvalidate('dom') ``` is to reload data which has been externally modified - what am i missing here?
Thanks for an awesome library!
Best regards,
Henrik
This question has an accepted answers - jump to answer
Answers
That's going to be a problem for DataTables. It expects to have full control over the DOM. It will manipulate the DOM to apply sorting, ordering, paging, etc. For example, if you have paging enabled and more than 10 rows in the table, it will only have the 10 needed actually in the DOM. HTMX can't know that, so we end up with a conflict. I'm not sure how the two could really work together to be honest. It might be possible if the rows have ids and you updated that way, but it isn't something I've tried - DataTables has its own internal reference to the TR and its cells, so if they are replaced, all bets are off.
Realistically you only want one library controlling the DOM for the table. If you can get the data alone and tell HTMX to leave the table alone, that's probably the best way.
Allan
But isn’t this exactly the point of the invalidate method - to scrap all internal references and recalculate them based on what’s currently in the html?
Just like when the datatable was first applied on the html table when page was first loaded.
My understanding is
rows().invalidate()
will only update rows that exited in the DOM when initialized. It won't add or remove rows which is what you are doing when replacing atr
. I built this simple example to deomonstrate:https://live.datatables.net/mohiwogu/1/edit
Click the
Replace Aston's TR
button and the row is replaced androws().invalidate()
is executed. Since the original row is removed and a new row is added Datatables doesn't update its cache with that new row. You can see this be searching forreplaced
.Click the
Run with JS
button to start over then clickUpdate Ashton
. The cell within the existing row is updated androws().invalidate()
works. Search forupdated
to verify.It would be a bit drastic but you could use
destroy()
ordestroy
and reinit Datatables if you want Datatables to scrap all internal references and recalculate.Possibly you can use Datatables API's, instead of HTMX, to update the table as explained in this FAQ.
I'm not familiar with HTML but could you change this code:
to something like this to stop the HTML update?
Or instead of using
htmx.ajax
use jQuery ajax() to send requests to your API's and use thesuccess
function to utilize the Datatables APIs to update the table.Kevin
Yes, exactly as Kevin says. Depending on the "direction" it will either:
innerHTML
for a cell). That reads the DOM values into the DataTables internal store, orinvalidate()
does not scan for new elements, removed element or replaced ones. Therows.add()
,rows().remove()
methods would be used to perform those actions.Consider paging - if DataTables and HTMX both controlled the DOM and the user clicked the DataTable control to flick to page 2, HTMX would have no idea where the previous elements have gone (since they are removed from the DOM) when it next does an update (i.e. a data change), and would redraw the table. DataTables wouldn't know that had happened, and still think it is correctly showing page 2's data. Cached filtering values would be out of date, as would sorting, etc.
Without a full integration between the two, there is simply no way for two libraries to control and manipulate the same DOM. This is true for all, not just DataTables and HTMX.
In Vue we use
v-once
to make Vue leave the table alone once it has been rendered. Let DataTables control the DOM. If HTMX has a similar option and you can feed it data, then that would work just fine.I do need to make some time to play with HTMX sometime!
Allan
Thanks a lot for the in-depth explanation. The purpose and function of
invalidate()
is now clear.What I ended up doing was the following:
It fills our needs. We don't have enough data to warrant server-side processing, and htmx provides us with all the dynamics we need. By having htmx talking care of data manipulation in the datatable, we can reuse e.g. error handling and user confirmation from htmx also here.
In fact, these methods bridging data tables and htmx are pretty much the only custom javascript we have in the whole application.
/Henrik
That looks like a really nice way of doing it. Thanks for sharing it with us!
Allan
you can publish the method calculateTrIdFromLocation(location)?
@rmbertolino - That post was from a year ago, so I'm not sure you'll get an answer. However, we can probably figure it out. What is the value of the
location
variable that you have? It probably just parses out theid
and then that can be used with a row selector (row()
) to get the required element.If you can link to your page showing the data data you are working with, that would be useful.
Allan