Destroy DataTables before Turbo caches the page

The back button restored a Turbo snapshot that still held DataTables'
injected search / length controls; re-init on turbo:load then stacked
another set each time. Tear every instance down on turbo:before-cache
so the cached snapshot is a plain table again.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Frank
2026-09-06 15:11:59 +02:00
co-authored by Claude Sonnet 5
parent 01d5fd13b2
commit 3c622d7dd8
+15 -2
View File
@@ -48,9 +48,15 @@ function columnFromTh(th, rowUrl) {
return col; return col;
} }
// Live DataTable instances, keyed by their <table> element. Used to tear them
// down before Turbo caches a page - otherwise the back button restores a
// snapshot that still contains DataTables' injected controls, and re-init
// stacks a second set of "search" / "entries per page" rows on top.
const instances = new Map();
function initDataTables(root = document) { function initDataTables(root = document) {
root.querySelectorAll('table.datatable').forEach((table) => { root.querySelectorAll('table.datatable').forEach((table) => {
if (table.dataset.datatable === 'false' || DataTable.isDataTable(table)) { if (table.dataset.datatable === 'false' || instances.has(table) || DataTable.isDataTable(table)) {
return; return;
} }
@@ -76,9 +82,16 @@ function initDataTables(root = document) {
}; };
} }
new DataTable(table, options); instances.set(table, new DataTable(table, options));
}); });
} }
function destroyDataTables() {
instances.forEach((dt) => dt.destroy());
instances.clear();
}
document.addEventListener('DOMContentLoaded', () => initDataTables()); document.addEventListener('DOMContentLoaded', () => initDataTables());
document.addEventListener('turbo:load', () => initDataTables()); document.addEventListener('turbo:load', () => initDataTables());
// Restore the plain <table> before Turbo snapshots the page for its cache.
document.addEventListener('turbo:before-cache', destroyDataTables);