how to properly destroy and reinitialize a datatable?

how to properly destroy and reinitialize a datatable?

waqaranwar2021waqaranwar2021 Posts: 16Questions: 3Answers: 0

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

  • allanallan Posts: 63,689Questions: 1Answers: 10,500 Site admin

    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.

                destroy: true,
                retrieve: true,
    

    You can't use these two together. It will always result in the behaviour of retrieve.

    Allan

  • waqaranwar2021waqaranwar2021 Posts: 16Questions: 3Answers: 0

    Sure, thanks alot Allan will try it out

  • waqaranwar2021waqaranwar2021 Posts: 16Questions: 3Answers: 0
    edited October 17

    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?

  • waqaranwar2021waqaranwar2021 Posts: 16Questions: 3Answers: 0

    the pagination "Showing 1 to 5 of 5 entries" is not being updated, that seems to be the problem.

  • chocchoc Posts: 102Questions: 12Answers: 9

    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

  • waqaranwar2021waqaranwar2021 Posts: 16Questions: 3Answers: 0

    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

  • rf1234rf1234 Posts: 3,021Questions: 88Answers: 421

    keep in mind that i have a normal table (with tr td th tags) that is converted into a datatable.

    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 ...

  • waqaranwar2021waqaranwar2021 Posts: 16Questions: 3Answers: 0

    thankyou rf1234 for your reply. that doesn't help and the whole table doesn't update

  • rf1234rf1234 Posts: 3,021Questions: 88Answers: 421

    Another one:
    https://datatables.net/reference/api/rows().invalidate()

    Try that with all rows like this:

    table.rows().every(function () { 
        this.invalidate(); // invalidate the data DataTables has cached for this row
    });
     
    // Draw once all updates are done
    table.draw();
    
  • rf1234rf1234 Posts: 3,021Questions: 88Answers: 421

    This is simpler and should do the job as well:

    // Invalidate and redraw all rows
    table
        .rows()
        .invalidate()
        .draw();
    

    if that doesn't work either you would probably have to "destroy" and recreate the data table whenever you add or delete rows.

  • waqaranwar2021waqaranwar2021 Posts: 16Questions: 3Answers: 0

    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.

  • allanallan Posts: 63,689Questions: 1Answers: 10,500 Site admin

    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

  • waqaranwar2021waqaranwar2021 Posts: 16Questions: 3Answers: 0
    edited October 23

    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.

  • chocchoc Posts: 102Questions: 12Answers: 9
    edited October 23

    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.

  • waqaranwar2021waqaranwar2021 Posts: 16Questions: 3Answers: 0

    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).

Sign In or Register to comment.