Help on correct usage DataTable and html updated data

Help on correct usage DataTable and html updated data

JensAlstedJensAlsted Posts: 5Questions: 2Answers: 0

I have a Rails 7 based application base on Turbo. I also have table with a checkbox (in a form) for each row to apply discount on the item represented by that row. The checkbox triggers a turbo stream update of the html.

As I read the FAQ i have to do a row.invalidate() when updating the html behind DataTable. I'm fully aware of the performance hit here, Im for now willing to just accept that.

I have made a callback that runs on given events, it is being called just fine and looks like this:

      dt_invalidate(event){
            //console.log(this.tableIdValue) shows the correct table id.  
            var table = document.getElementById(this.tableIdValue)
            //console.log(table) Shows that I got the correct table
            //console.log(window.jQuery().jquery) shows my jQuery version to be 3.6
            var dt  = window.jQuery("#" + this.tableIdValue).DataTable()
            dt.rows().every(function (rowIdx, tableLoop, rowLoop) {
                //console.log(rowIdx) prints index 0-13 matches number of rows = 14 and debugger Bookmarklet information. 
                this.invalidate("dom"); // invalidate the data DataTables has cached for this row
            });
          //$(window).trigger('resize');
          //window.dispatchEvent(new Event('resize'));
          //dt.columns.adjust().draw();
        }

My issue is that it does not really seem to work as expected. I certainly dont think that it is problem with DataTables but rather with my understanding of what I can do with it and how.

What I experience is that data is correctly is shown in the browser when i click on the checkbox and the server roundtrip complets. I can click several of them and it all works great. I check this by "View Source" to get the actual HTML.
If I choose to reorder a column then the checkbox state is the same but values are now back to what is was when the page loaded. I check this by "View Source" to get the actual HTML which is the correct value send by server and by comparing to the developer console elements tab which hold the now incorrect initial values. This is still causing me some head scratching why these are not the same. I thought that DataTables did not use the DOM.
If i hit f5 for reload all data comes back correctly as it is persisted for each roundtrip.

I have then been considering if the invalidation is not sufficient alone. Maybe i need to "redraw" or at least "reload" the html back into DataTables. I have tried each of the following:

        $(window).trigger('resize');
        window.dispatchEvent(new Event('resize'));
        dt.columns.adjust().draw();

and each lead to same problem as before but the with twist that when i click row number 2 then row number 1 flips back to the cached value.

I hope there this some detail of the documentation that i missed that either just tells me to stop my madness or whatever it is that i need to do.

Any hints and help is much appreciated.

Thanks
Jens

This question has accepted answers - jump to:

Answers

  • allanallan Posts: 63,214Questions: 1Answers: 10,415 Site admin

    Hi Jens,

    Can you show me how you are updating the HTML please? Or even better, a provide a link to a page showing the issue?

    Allan

  • kthorngrenkthorngren Posts: 21,173Questions: 26Answers: 4,923

    Datatables uses a data cache to store the table data and places in the DOM only those rows displayed on the page. As it sounds like you understand from the FAQ Datatables knows nothing about table updates made directly in the DOM and to use some thing like row().invalidate() to refresh the Datatables cache.

    I check this by "View Source" to get the actual HTML.

    Hmm, I'm not familiar with Rails 7 nor how the turbo stream update of the html. works but it sounds like the actual DOM might not be updated?

    See this simple example:
    http://live.datatables.net/ketiguwi/1/edit

    Click the Update Ashton button and the Position will change to Updated. Search for Updated and you will see its not found. Click the Invalidate button then try the same search to see it working.

    You can use dt.rows().invalidate().draw() instead of the below loop if you wish to invalidate all rows.

          dt.rows().every(function (rowIdx, tableLoop, rowLoop) {
              //console.log(rowIdx) prints index 0-13 matches number of rows = 14 and debugger Bookmarklet information.
              this.invalidate("dom"); // invalidate the data DataTables has cached for this row
          });
    

    Or if you know the row or rows to update you could supply them as a row-selector.

    Is it possible to provide a link to your page or a test case replicating the issue so we can take a look?
    https://datatables.net/manual/tech-notes/10#How-to-provide-a-test-case

    Kevin

  • JensAlstedJensAlsted Posts: 5Questions: 2Answers: 0

    Thanks for the reply Kevin.

    Rails Turbo is at it basis a DOM mutator that sends HTML over the wire and thus avoids page tear downs(and most likely many other things I'm not fully aware of, im by no means an expert on the subject:) )

    But you raise a valid question:
    Do I actually see the DOM update? I will start double checking that. Naturally I'm already asking myself why I did what I did for checking the updates in browser.

    I will also have go through the examples and try the dt.rows().invalidate().draw() or the row-selector type. Both should be doable.

    If nothing of that pans out, I will see i can create a short example or free that application page from the application security context in an easy way.

    Last resort is to use json and write some more JS and use the Api of DataTables.

    Whatever happens, I'll post an update here.

    Again, thanks for sharing your thoughts.
    Jens

  • allanallan Posts: 63,214Questions: 1Answers: 10,415 Site admin
    Answer ✓

    Hi Jens,

    It depends a little bit on how the DOM mutation is working if DataTables would even see it. DataTables retains a link to the original tr and td elements. So if the mutation replaces either of those, and not just the child nodes of the td, DataTables would never see it.

    Allan

  • JensAlstedJensAlsted Posts: 5Questions: 2Answers: 0
    edited December 2022

    Hi Allan

    I think that you have just struck my core issue.

    I replace the entire <tr> and thus DataTables never see it. I noticed this due to some DataTables Class names (even/odd etc) got removed while I was following up on Kevins question from yesterday. This was my follow up point today if that was causing me issues.

    Just be sure that understand your comment on children correct:

    <td>my_value</td>

    has no children and if replace the entire <td> i end up in the same situation.

    If i do something like:
    <td><span id="my_id">my_value<span></td>

    and replace <span id="my_id">my_value<span> with <span id="my_id">my_other_value<span> then from a DataTables point of view it should be workable ?

    Thanks for the answer.
    Jens

  • JensAlstedJensAlsted Posts: 5Questions: 2Answers: 0

    Hi

    Kevin and Allan, thanks for your help. I would not have come to this conclusion without it.

    For anyone else that comes by here with a similar problem:

    I have implemented the child solution with span as outlined above. That is, I wrapped the value in <span id="spanid"> .

    Then in a stimulus controller that wraps DataTable I have:

    document.documentElement.addEventListener('turbo:before-stream-render',this._dt_invalidate)
    

    and

        dt_invalidate(event){
            var table = document.getElementById(this.tableIdValue)
            var dt  = window.jQuery("#" + this.tableIdValue).DataTable()
            dt.rows().invalidate().draw()//ToDo tighter invalidation strategy
    
        }
    

    The span is simply just handled by turbo_stream on the rails side:

    <%= turbo_stream.replace "spanid_#{@some.id}",
                             partial: "some/partial_span",
                             locals: { some: @some} %>
    

    Thanks
    Jens

  • allanallan Posts: 63,214Questions: 1Answers: 10,415 Site admin
    Answer ✓

    Hi Jens,

    Great to hear you found a solution.

    Just to clarify:

    <td>my_value</td> has no children

    It actually does. It has a text node child (which contains my_value in this case). It doesn't have any elements as children though, which might be causing the confusion there.

    Ideally the DOM mutator would be able to work with the text nodes mitigating the need for loads of ids, but depending on how it works, that might or might not be possible.

    Allan

Sign In or Register to comment.