Refresh data (JSON) from server source -- keep open rows open

Refresh data (JSON) from server source -- keep open rows open

AnonymoleAnonymole Posts: 13Questions: 2Answers: 1

I've got a parent/child dataset presenting nicely.

The data does however change frequently. So I thought I'd fetch it from the server (a deeply nested JSON object) and pass in the updated data to the table and call draw:

if ($('#containerTable') && $('#containerTable').DataTable().rows().length > 0 && $('#containerTable').DataTable().rows()[0].length > 0) {
    var table = $('#containerTable').DataTable();
    table.data = providerList;
    table.draw();
    return;
}

If I don't have any rows then I go ahead and build the whole table again.

I'd do that anyway, except that I'd like to keep any expanded rows (containing a child table) open after the refresh (quality user experience and all that).

But the above doesn't actually refresh the data. Although I think it repaints the table.

Aside from trying to use ajax.reload() (which I'd do except that the JSON contains more than just the table contents) how might I go about updating the table's data?

Answers

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

    What you will need to do is loop over the rows in the table to determine which are currently "open", before you make the Ajax request, then once the Ajax request has completed, loop over the new rows in the table and reopen them as required based on which were previously open.

    This is something that I might include in a future version of DataTables, but for the moment, that is how it needs to be done.

    Allan

  • AnonymoleAnonymole Posts: 13Questions: 2Answers: 1

    I suspected as much. Thanks for taking the time time answer.

  • AnonymoleAnonymole Posts: 13Questions: 2Answers: 1

    You don't have an example of how to loop over the rows to determine which are open do you? Like an end to end solution for this problem of reopening child tables?

  • AnonymoleAnonymole Posts: 13Questions: 2Answers: 1
    edited June 2015

    I'm absolutely baffled here. There seem to be so many variations of datatable, fnThisOrThat, nodes, rows, trs, indexes...

    Here's what I've got:

    // Add event listener for opening and closing details
    $('#containerTable tbody').on('click', 'td.details-control', function () {
        var tr = $(this).closest('tr');
        var table = $('#containerTable').DataTable();
        var row = table.row(tr);
    
        // This row is already open - close it
        if (row.child.isShown()) {
            row.child.hide();
            tr.removeClass('shown');
            rowIndex = row[0][0];
            var idx = openTableRows.indexOf(rowIndex);
            openTableRows.splice(idx, 1);
            Cookies("openRows", openTableRows);
        }
            // Open this row
        else {
            row.child(formatChildTable(tr, row.data())).show();
            tr.addClass('shown');
            rowIndex = row[0][0];
            if (openTableRows.indexOf(rowIndex) < 0)
                openTableRows.push(rowIndex); // push the row index into the openrows array
            Cookies("openRows", openTableRows);
        }
    });
    

    openTableRows = []

    And Cookies is this: * https://github.com/js-cookie/js-cookie

    And then on refresh:

    function reOpenRows() {
        var openRows = Cookies("openRows");
        if (!openRows)
            return;
        openTableRows = eval(openRows);
        var table = $('#containerTable').DataTable();
        $(table.rows().nodes()).each(function (idx, tr) {
            if (openTableRows.indexOf(idx) >= 0) {
                $(tr).addClass("shown");
                //table.row($(tr)).child.show();  // DON'T WORKIE
                //$(tr).click();  // DON'T WORKIE
                //$(tr).trigger('click');  // DON'T WORKIE
            }
        });
    }
    

    But I don't think this is the right way - obvisously - as this does not even come close to working... Any help would be appreciated.

  • AnonymoleAnonymole Posts: 13Questions: 2Answers: 1

    AHHHHH -- got it.

    One has to fully reproduce the child table fill on child.show()

    function reOpenRows() {
        var openRows = Cookies("openRows");
        if (!openRows)
            return;
        openTableRows = eval(openRows);
        var table = $('#containerTable').DataTable();
        $(table.rows().nodes()).each(function (idx, tr) {
            if (openTableRows.indexOf(idx) >= 0) {
                row = table.row(tr);
                row.child(formatChildTable(tr, row.data())).show();
                $(tr).addClass("shown");
            }
        });
    }
    
  • allanallan Posts: 63,498Questions: 1Answers: 10,470 Site admin

    Yes you will need to do that for new rows. Existing rows would have their child rows available still and could still be shown if needed.

    Good to hear you got it sorted.

    Allan

  • AnonymoleAnonymole Posts: 13Questions: 2Answers: 1

    I do a JSON fetch and table rebuild every 60 seconds. There are no existing rows. I realize that there's ways (I assume) to refresh the table's data (I guess) and invalidate the table or instruct it to reconcile itself. I could barely get this version working... I'm OK with this method. I will say that your tools super -- but, the myriad versions and conflicting styles of accomplishing something make it confusing to use.

  • AnonymoleAnonymole Posts: 13Questions: 2Answers: 1

    Update: I could not use the IDX of the row. After sorting the row indexes get all rearranged. So I had to rely upon using the first cell of the row as a key to use to identify any one row. I then loop through the saved cookie keys looking for the identical text.

    $(table.rows().nodes()).each(function (idx, tr) {
        rowIDText = $(tr).find("td:first").text();
        if (openTableRows.indexOf(rowIDText) >= 0) {
    

    And in the row click event:

    rowIDText = $(tr).find("td:first").text();
    var idx = openTableRows.indexOf(rowIDText);
    openTableRows.splice(idx, 1);
    
    ###
    
    rowIDText = $(tr).find("td:first").text();
    if (openTableRows.indexOf(rowIDText) < 0)
        openTableRows.push(rowIDText); // push the row index into the openrows array
    
    
This discussion has been closed.