how to properly destroy and reinitialize a datatable?
how to properly destroy and reinitialize a datatable?
Description of problem:
i am having problem destroying and re-initializing a datatable. i have created a generic datatable component in react to be used on different tables. but the problem is that when the data in the table changes then the changes are not seen properly on the table. for example after deleting an item from table, the item still can be seen in the table. and after deleting and adding an item to the table the page crashes with an error. all of this problem is the datatable is not properly being destroyed or being re-initialized properly. i have used options like .destory(), destroy: true and retrieve: true but these options seem not to be working properly. Here is the code for the MasterDataTable component:
import React, { useEffect, useRef, useState } from 'react';
import $ from 'jquery';
// import 'bootstrap/dist/css/bootstrap.min.css';
import 'jquery/dist/jquery.min';
import "datatables.net-dt/js/dataTables.dataTables";
import "datatables.net-dt/css/dataTables.dataTables.min.css";
import "datatables.net-buttons/js/buttons.colVis";
import "datatables.net-buttons/js/buttons.html5";
import "datatables.net-buttons/js/buttons.print";
import "datatables.net-buttons/js/dataTables.buttons";
// import 'jszip';
import JSZip from 'jszip';
import 'pdfmake';
// import 'pdfmake/build/pdfmake';
// import 'pdfmake/build/vfs_fonts';
import pdfMake from "pdfmake/build/pdfmake";
import pdfFonts from "pdfmake/build/vfs_fonts";
import DataTable from 'datatables.net-buttons-dt';
window.JSZip = JSZip;
pdfMake.vfs = pdfFonts.pdfMake.vfs;
const MasterDataTable = (prop) => {
const { tableId, tableData } = prop
const dataTableRef = useRef(null);
useEffect(() => {
if ($.fn.DataTable.isDataTable(`#${tableId}`)) {
$(`#${tableId}`).DataTable().destroy();
console.log("destroyed")
}
if(tableData?.length > 0){
dataTableRef.current = new DataTable(`#${tableId}`, {
pagingType: 'full_numbers',
pageLength: 10,
processing: true,
responsive: true,
destroy: true,
retrieve: true,
dom: 'Bfrtip',
orientation: tableData[0] && tableData[0].length > 4 ? 'landscape' : 'portrait', // Set orientation based on column count
pageSize: tableData[0] && tableData[0].length > 4 ? 'A3' : 'A4', // Adjust page size based on the number of columns
buttons: [
{
extend: 'copyHtml5',
exportOptions: {
columns: ':visible',
modifier: {
page: 'all'
},
format: {
body: (data, row, column, node) => {
// Dynamically handle the Status column
if ($(node).closest('td').hasClass('status-column')) {
return $(data).find('input').is(':checked') ? 'True' : 'False';
}
return $(node).text().trim();
}
},
stripHtml: true,
},
},
{
extend: 'csvHtml5',
exportOptions: {
columns: ':visible',
modifier: {
page: 'all'
},
format: {
body: (data, row, column, node) => {
// Dynamically handle the Status column
if ($(node).closest('td').hasClass('status-column')) {
return $(data).find('input').is(':checked') ? 'True' : 'False';
}
return $(node).text().trim();
}
},
stripHtml: true,
}
},
{
extend: 'excelHtml5',
exportOptions: {
columns: ':visible',
modifier: {
page: 'all'
},
format: {
body: (data, row, column, node) => {
// Dynamically handle the Status column
if ($(node).closest('td').hasClass('status-column')) {
return $(data).find('input').is(':checked') ? 'True' : 'False';
}
return $(node).text().trim();
}
},
stripHtml: true,
}
},
{
extend: 'pdf',
exportOptions: {
columns: ':visible',
stripHtml: false,
modifier: {
page: 'all'
}
}
},
{
extend: 'print',
exportOptions: {
columns: ':visible',
stripHtml: false,
modifier: {
page: 'all'
}
}
},
'colvis',
],
initComplete: ()=> {
// $(`#${tableId}`).addClass('table table-bordered table-hover toggle-circle custom-table table');
}
});
console.log(`DataTable with ID #${tableId} initialized.`);
}
}, [tableId, tableData]);
// return null; // No need to render anything
};
export default MasterDataTable;
Answers
Have you tried the
datatables.net-react
component? It has support for reactive data and should just update automatically when you delete data from a state. Example of that here.You can't use these two together. It will always result in the behaviour of
retrieve
.Allan
Sure, thanks alot Allan will try it out
Allan the problem of table not updating resolved, now it is updating on add/delete (i just used retrieve:true and removed all destroy functionalities and even destroy:true). Thank you. but another problem occurring is that for pagination it is saying:
Showing 1 to 5 of 5 entries.
instead it should say:
Showing 1 to 4 of 4 entries
because 1 entry was deleted.
Can you please share how to resolve that?
the pagination "Showing 1 to 5 of 5 entries" is not being updated, that seems to be the problem.
Apply a key to Datatable
See: https://datatables.net/forums/discussion/79833/react-datatable-isdatatable-not-working
React will handle the destroy.
you may also follow this question:
https://datatables.net/forums/discussion/80028/table-will-initialize-4-times-when-using-react-strictmode
If you’re using StrictMode, that may show some unexpected behaviors when you use datatables with other features
Thanks for your reply choc, but the issue of pagination not being updated still persists even after giving a key to the table. keep in mind that i have a normal table (with tr td th tags) that is converted into a datatable. so it is directly manipulating the DOM in react. the table you have on the other hand has data being passed from ajax.json file hence it is not a normal table. by the way thanks for the reply choc
Ok, I guess you could use the "draw" method after the conversion of your table into a datatable. That should also update the pagination. Why not give it a try.
https://datatables.net/reference/api/draw()
The default "paging" option is "full-reset":
"the ordering and search will be recalculated and the rows redrawn in their new positions. The paging will be reset back to the first page."
That would just be: table.draw();
But: not sure whether that also recalculates the pagination ...
thankyou rf1234 for your reply. that doesn't help and the whole table doesn't update
Another one:
https://datatables.net/reference/api/rows().invalidate()
Try that with all rows like this:
This is simpler and should do the job as well:
if that doesn't work either you would probably have to "destroy" and recreate the data table whenever you add or delete rows.
rf1234 thankyou, but table.rows().invalidate().draw(); is not working too. and i have been trying to destroy and reinitialize the table from the start but it isn't working. the closest i got was by using retrieve:true only instead of any destroy functonality as informed by Allan (thankyou Allan). that way all worked except the pagination.
I think I'd need a link to a page showing the issue please? Or better yet a link to a Stackbltiz example (perhaps based off one from the manual page) demonstrating the error so I can debug it.
Allan
Here is the link Allan:
https://stackblitz.com/edit/vitejs-vite-hitpe5?file=src%2FMasterDataTable.js
there are a few more problems like numbering of S No. goes to the left upon adding a new row. And the table shows nothing if the line is commented out:
if(tableData?.length > 0){
in MasterDataTable.js. Because it will only show all the options like sorting, searching, pagination and buttons if there is data. And exporting to pdf make doesn't support rendering html. Thanks for your reply Allan.
I would recommend using slot to render the button in the action column, and using
<DataTable>
instead of<table>
(or both). Perhaps Allan can comment on this as I only use<DataTable>
. Not sure why you use both<table>
and<DataTable>
. Is there a specific use for this?I have modified and simplified your demo: https://stackblitz.com/edit/vitejs-vite-fgmzpj?file=src%2FApp.tsx
without button plugins. The
S No.
type is correct now.choc thanks for your reply,
Actually we have a webapp having 250+ pages in react. all those pages have tables with simple tr td th tags. now to convert all those tables into a DataTable format (passing tableData as a variable instead of simple tr td tags and converting their html into specific html format because there are buttons inside the tables like count, delete, edit button etc.) would be a hectic/time taking job. we're close to making a proper datatable with all the functionalities like searching, sorting, pagination, print, PDF, CSV (all while having the table with simple tr td th tags).