Stale rows displayed after Ajax data update with stateSave enabled
0 reputation · 15 Jul 2026, 19:01 UTC
0 reputation · 15 Jul 2026, 19:01 UTC
Goal: prevent the table from showing rows that no longer match the saved filter or page index after an Ajax data update while stateSave is enabled.
When stateSave restores pagination, search, and column order before the table draws, a subsequent Ajax reload can replace the underlying data set. If the saved state refers to indices or values that are no longer present, the plugin may display stale rows, creating a mismatch between UI state and actual data.
The unresolved decision is whether DataTables should automatically invalidate saved state when the Ajax data source signals a change, or leave this responsibility to developers via custom callbacks.
Should DataTables automatically clear saved state when the Ajax data source signals a change? If not, what is the recommended pattern for developers to detect and handle stale state? Are there any existing callbacks or events that can be relied upon to trigger state invalidation safely?
34775 reputation · 16 Jul 2026, 04:27 UTC
No — DataTables does not automatically invalidate saved state when your Ajax data changes, and there is no built-in event that signals "the data source changed, clear the state." State invalidation is the developer's responsibility. The reliable pattern is: detect the data change yourself (ideally with a server-supplied version marker), and clear or reset state before the table applies it, not after a stale draw.
This part is well-established behavior. stateSave stores page index, search term, ordering, and column visibility in localStorage (or a cookie) as plain values. Those values have no link to the live data set. On reload, DataTables restores the saved state first and then draws against whatever data the Ajax response returned. If the saved page index points past the end of the new, smaller result set, or the saved search term matches nothing, you get an empty or mismatched view — the "stale rows" symptom. DataTables treats state as user preference, not as a cache of data, so it deliberately never ties the two together.
The robust approach is to make the server tell you when the data changed, then act on that signal:
dataVersion field.var lastVersion = localStorage.getItem('myTable_dataVersion');
var table = $('#example').DataTable({
ajax: '/api/rows',
stateSave: true,
xhr: function () { /* DataTables 1.x: use ajax.dataSrc instead */ }
});
table.on('xhr.dt', function (e, settings, json) {
if (!json || json.dataVersion === undefined) return;
if (lastVersion !== null && String(json.dataVersion) !== lastVersion) {
table.state.clear(); // drop stale page/search/order
table.page('first'); // land somewhere sane
}
localStorage.setItem('myTable_dataVersion', json.dataVersion);
lastVersion = String(json.dataVersion);
});The xhr.dt event fires when an Ajax request completes, before the draw consumes the data, which makes it a safe hook for this check. state.clear() removes the stored state; the next state.save() (automatic on later draws) writes a fresh one.
A weaker client-side fallback is to validate the restored state after the draw: compare table.page.info().page against table.page.info().pages, and if the current page is out of range, jump to a valid page. This fixes out-of-range pagination but cannot detect subtle changes (same row count, different content), which is why the server-side version marker is preferred.
stateSave and disorients users who expect their filter and page to survive refreshes.state.clear(), xhr.dt) assume DataTables 1.10+; verify against your installed version, since the 2.x line renamed some options and events.One diagnostic worth confirming before implementing: does your Ajax endpoint already return anything that changes when the data set changes (a total count, an etag)? If yes, use that as the version signal instead of adding a new field.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.