2

The docs say that I should be able to set the page via DataTablesApiInstance.page(pageNumber), but I can't get it to work.

All the other API methods like search and order seem to work fine.

Here's my code:

$(document)
    .on('preInit.dt', (ev, settings) => {
        let tableId = ev.target.id;
        let tableState = _.get(['datatables', tableId], history.state) || {};

        let api = new $.fn.dataTable.Api(settings);

        if(tableState.hasOwnProperty('page')) {
            api.page(tableState.page); // <-- problem is here; page doesn't get set
        }

        if(tableState.hasOwnProperty('search')) {
            api.search(tableState.search);
        }

        if(tableState.hasOwnProperty('order')) {
            api.order(tableState.order);
        }

        const setState = (key, value) => {
            history.replaceState(_.set(['datatables', tableId, key], value, history.state), '');
        };

        api.on('page', ev => {
            let info = api.page.info();
            // console.log('page', tableId, info.page);
            setState('page', info.page);
        });

        api.on('order', ev => {
            let order = api.order();
            // console.log('order', tableId, order);
            setState('order', order);
        });

        api.on('search', ev => {
            setState('search', api.search());
        });
    });

The method is hit, but the page isn't set. Am I using the wrong API method? Is there another way to set the page before the data loads?

I'm using datatables.net@1.10.12.


If I defer the call to init instead of preInit then the correct page number is highlighted, but the data is still from the first page. If I add a 0ms delay on top of that (as below), it does work, but causes a 2nd data fetch + draw.

if(tableState.page) {
    api.on('init', ev => {
        setTimeout(() => {
            api.page(tableState.page).draw('page');
        }, 0);

    });
}

How can I set the page without incurring a 2nd ajax request?

mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • You need to `draw()` the page as well -> `api.page(tableState.page).draw()` – davidkonrad Dec 11 '16 at 09:24
  • @davidkonrad Thanks, but I tried that too. `.draw('page')` as well. Didn't work. I don't think it should be necessary on `preInit` though -- it draws right after. – mpen Dec 11 '16 at 18:43
  • Found this: https://datatables.net/forums/discussion/comment/86374/#Comment_86374 Looks like this issue was never resolved. I opened a ticket: https://datatables.net/forums/discussion/39396/api-page-n-does-not-work-in-preinit-or-init – mpen Dec 11 '16 at 19:04

2 Answers2

3

You can use displayStart option to define the starting point for data display when using DataTables with pagination as recommended by the author of jQuery DataTables.

It works correctly with table in server-side processing mode and only 1 Ajax request is performed.

var table = $("#example").DataTable({
     "processing": true,
     "serverSide": true,
     "ajax": "/test",
     "displayStart": 200     
 });

From the documentation:

Note that this parameter is the number of records (counting from 0), rather than the page number, so if you have 10 records per page and want to start on the third page, it should be 20 rather than 2 or 3.

Gyrocode.com
  • 57,606
  • 14
  • 150
  • 185
  • The problem with that is that I don't want to copy this code to every DataTable I use on my site. I'm trying to do a catch-all, which is why I'm listening for the `preInit` event on `document`. If I could modify the settings from in there, I could make this work, but that's not possible is it? – mpen Dec 11 '16 at 22:27
  • 1
    @mpen, there could be other alternatives but before we dive deep into this, why you're not using [`stateSave`](https://datatables.net/reference/option/stateSave) instead which saves/restores pagination as well as other parameters such as search, order, etc.? You can use [`stateSaveCallback`](https://datatables.net/reference/option/stateSaveCallback) and [`stateLoadCallback`](https://datatables.net/reference/option/stateLoadCallback) if you want to implement your own state-saving mechanism, no need for `preInit.dt` event handler. – Gyrocode.com Dec 12 '16 at 02:43
  • Does `stateSave` only work on page reload/back? Or does it remember it forever? Because I only want the state to be restored when the user presses "back" which is why I started going down this road. – mpen Dec 12 '16 at 03:42
  • @mpen, See [this post](http://stackoverflow.com/questions/40550946/getting-datatables-to-keep-its-state-when-the-user-clicks-the-back-button-witho) on the topic. – Gyrocode.com Dec 12 '16 at 05:37
  • Ahah. That is exactly what I'm trying to do. I didn't see that before, but I can't say I'm fond of Dex's solution. Adding JS to every link to the page to clear the state is a pretty awful hack. My solution seems similar to [Aliester's](http://stackoverflow.com/a/40718496/65387), except I didn't really want to alter the hash. I suppose I could do what I want with the state save+load callbacks. I will try that out, thanks! – mpen Dec 12 '16 at 07:14
1

This doesn't (directly) answer the question of how to set the page in the preInit, but it solves my problem.

We can use the stateLoadCallback to load the state (including page) from the history API instead of using localStorage as the default implementation does (which will remember the state even when navigating away and then back again).

$.extend(true, $.fn.dataTable.defaults, {
    stateSave: true,
    stateSaveCallback: (settings, data) => {
        let tableId = settings.nTable.id;
        if(!tableId) {
            // console.warn(`DataTable is missing an ID; cannot save its state`);
            return;
        }
        history.replaceState(_.set(['datatables', tableId], data, history.state), '');
    },
    stateLoadCallback: settings => {
        let tableId = settings.nTable.id;
        if(!tableId) {
            console.warn(`DataTable is missing an ID; cannot load its state`);
            return;
        }
        return _.get(['datatables', tableId], history.state) || null;
    }
});
mpen
  • 272,448
  • 266
  • 850
  • 1,236