jquerydatatablespagination

DataTables not paging correctly with popstate


I'm using DataTables with serverSide processing. On popstate the table is redrawn with loaded values. Everything is working nicely except for one problem: when I go from a state where the page for the loaded state isn't available, it won't load the correct page for the loaded state, if that makes sense.

So for example:

  1. If I'm in a state with 2 or more pages available, and then push the "back" button to a state on page 2, it will correctly load page 2.
  2. If I'm in a state with only 1 page available, and then push the "back" button to a state on page 2, it will load page 1.

Edit: I realize now that this is because of this in the page() doc:

Note that if you attempt to show a page which does not exist using the set format of this method, DataTables will not throw an error, but rather reset the paging to the first page.

The problem is that with serverSide processing, DataTables doesn't know how many pages there are until the table is drawn, so when the number of pages increases after doing a manual draw(), this leads to the problem I'm describing. There doesn't seem to be a way to coerce DataTables to go to the page anyway, so the only option would be to draw twice.

Here's the (simplified) code:

$(document).ready(function() {
    myTable.on("draw", function() {
        setState(); // history.replaceState or history.pushState
        saveTableOrder(); // save to localStorage
        saveTableLength(); // save to localStorage
    });
    
    $(window).on("popstate", function() {
        myTable
            .search(loadTableSearch()) // load from history.state
            .order(loadTableOrder()) // load from history.state or localStorage
            .page.len(loadTableLength()) // load from history.state or localStorage
            .page(loadTablePage()-1) // zero-indexed; load from history.state
            .draw(false); // same result with "full-hold" argument
    });
});

Solution

  • It seems that, in these cases, the only way around this is to either draw the table twice, or to destroy and reinitialize the table. Below is an example of how to draw the table twice.

    $(document).ready(function() {
        let redraw = false;
    
        myTable.on("draw", function() {
            // make sure we don't just reload page 1
            let page = loadTablePage();
            redraw = redraw && page > 1 && page <= myTable.page.info().pages;
    
            if (redraw) {
                redraw = false;
                myTable.page(page-1).draw("page");
            }
            else {
                setState(); // history.replaceState or history.pushState
                saveTableOrder(); // save to localStorage
                saveTableLength(); // save to localStorage
            }
        });
        
        $(window).on("popstate", function() {
            let page = loadTablePage(); // load from history.state
            redraw = page > 1 && page > myTable.page.info().pages;
            
            myTable
                .search(loadTableSearch()) // load from history.state
                .order(loadTableOrder()) // load from history.state or localStorage
                .page.len(loadTableLength()) // load from history.state or localStorage
                .page(page-1)
                .draw(false);
        });
    });