8
votes

I am working on the angular based project. I am using datatables to display data. When I try to do some modifications on the table, I get the following error.

DataTables warning: table id=DataTables_Table_0 - Cannot reinitialise DataTable. For more information about this error, please see http://datatables.net/tn/3

7

7 Answers

13
votes

I think it is because you are using [dtTrigger]="dtTrigger" in Angular DataTables and rerendering the table on the same page. If you have this problem you should use the following trick to handle dtTrigger

<table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="table">

Make sure you do not use this.dtTrigger.next() on ngOnInit()

ngAfterViewInit(): void {
    this.dtTrigger.next();
}

Rerender it when you use the second time

rerender(): void {
  this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
     dtInstance.destroy();
     this.dtTrigger.next();     
  });
}
4
votes

I solved this problem by removing the following code in *.ts file:

dtOptions: DataTables.Settings = {};
 this.dtOptions = {
};
1
votes

I am using DataTable in Angular7 and Bootstrap4

Step1: Install the package

npm i angular-datatables@6 [email protected] [email protected] --save

Step2: In angular.json

"styles": [ "./node_modules/datatables.net-dt/css/jquery.dataTables.css" ], "scripts": [ "node_modules/datatables.net/js/jquery.dataTables.js" ],

Step3: Inside app.module.ts

import { DataTablesModule } from 'angular-datatables';
imports: [
    .......
    DataTablesModule
]

Step4: Inside html

<table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" >...</table>

Step5: Inside ts

import { Component, OnInit, AfterViewInit, OnDestroy, ViewChild  } from '@angular/core';
declare var jQuery:any;
import { DataTableDirective } from 'angular-datatables';
import { Subject } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../environments/environment';


export class YourComponent implements OnInit, AfterViewInit, OnDestroy {
    @ViewChild(DataTableDirective) dtElement: DataTableDirective;
    dtOptions: DataTables.Settings = {};
    dtTrigger: Subject<any> = new Subject();
    ajxrequrl: string = environment.hostUrl + '/api/userList'; 
    start: number = 0; length: number = 10; draw: number = 1;
    postparams = {};

    constructor( private _http: HttpClient ) { }

    getListData(filterData, t) {
        //console.log(filterData);
        var zone = (filterData.zone != undefined ) ? filterData.zone : 0 ;
        var state = (filterData.state != undefined ) ? filterData.state : 0 ;
        var studentType = (filterData.studentType != undefined ) ? filterData.studentType : 0 ;
        var status = (filterData.status != undefined ) ? filterData.status : 0 ;
        var grade = (filterData.grade != undefined ) ? filterData.grade : 0 ;
        var startDate = (filterData.startDate != undefined ) ? filterData.startDate : 0 ;
        var endDate = (filterData.endDate != undefined ) ? filterData.endDate : 0 ;

        const that = this;
        this.dtOptions = {
            pagingType: 'full_numbers',
            pageLength: this.length,
            displayStart: this.start,
            autoWidth: false,
            serverSide: true,
            processing: true,
            searching: true,
            order: [],
            columnDefs: [ {
                'targets': [0], /* column index [0,1,2,3]*/
                'orderable': false, /* true or false */
            }],

            ajax: (dataTablesParameters: any, callback) => {
                var orderColumn = ''; var orderBy = ''; var order = 0;
                if(dataTablesParameters.order.length) {
                    var sortarr = ['classId', 'full_name', 'age', 'status', 'grade',  'zone', 'state', 'type', ... <all columns>];
                    orderColumn = sortarr[dataTablesParameters.order[0].column]; 
                    orderBy = dataTablesParameters.order[0].dir;
                    order = 1;
                }   

                /* Sending data through GET */
                /* 
                that.getparams = "?start="+dataTablesParameters.start
                +"&length="+dataTablesParameters.length
                +"&order="+order
                +"&orderColumn="+orderColumn
                +"&orderBy="+orderBy
                +"&zone="+zone
                +"&state="+state
                +"&studentType="+studentType
                +"&status="+status
                +"&grade="+grade
                +"&startDate="+startDate
                +"&endDate="+endDate;
                //+"&search="+encodeURI(dataTablesParameters.search.value);

                that._http.get(that.ajxrequrl + that.getparams, {}).subscribe(resp => {
                */

                /* Sending data through POST */
                that.postparams = {
                    start: dataTablesParameters.start, 
                    length: dataTablesParameters.length, 
                    order: order, 
                    orderColumn: orderColumn, 
                    orderBy: orderBy, 
                    search: dataTablesParameters.search,
                    //filterData: filterData
                    zone: zone,
                    state: state,
                    studentType: studentType,
                    status: status,
                    grade: grade,
                    startDate: startDate,
                    endDate: endDate
                };

                //jQuery('.dataTables_filter label input').attr("placeholder", "CL Contract ID or Customer Name or Case No");
                //jQuery('.dataTables_filter label input').css({'width': '350px', 'display': 'inline-block'});

                this._http.post( that.ajxrequrl, that.postparams, {} ).subscribe(
                    resp => {
                        that.listData = resp['data'];
                        that.start = resp['start'];
                        callback({
                            recordsTotal: resp['recordsTotal'],
                            recordsFiltered: resp['recordsFiltered'],
                            data: []
                        });
                    }, 
                    error => {
                        console.log(error);
                    }   
                );
            }
        };

        if(t == 1) {        
            this._othercaseService.filterList(filterData).subscribe(
            (resp) => {
                this.rerender();
                this.listData = resp['data'];
                if(resp['status'] == 0) {
                    //this.resetForm();
                }
            });
        }
    }

    ngOnDestroy(): void {
        // Do not forget to unsubscribe the event
        this.dtTrigger.unsubscribe();
    }

    rerender(): void {
        this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
            // Destroy the table first
            dtInstance.destroy();
            // Call the dtTrigger to rerender again
            this.dtTrigger.next();
        });
    }   

    ngAfterViewInit() {
        this.dtTrigger.next();

        this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
            dtInstance.on( 'draw.dt', function () {
                if(jQuery('.dataTables_empty').length > 0) {
                    jQuery('.dataTables_empty').remove();
                }
            });
        });
    }

    onSubmit(formData: NgForm) { // This function is called after a filter form searched
        this.getListData(formData, 1);
    }

    resetForm(pageStart: number = 1) {
        if(!pageStart) this.start = 0;
    }

    deleteUser(pkId) {
        /* After Delete code */
        this.getListData({}, 0);
    }
}

Step6: Inside your controller api call

module.exports.userList = (req, res, next) => {
    let reqData = req.body;

    var sql = 'SELECT .... FROM ....';
    /* ----- started changes for filter (just example)----- */
    sql = (reqData.grade) ? sql + ' AND grade = "' + reqData.grade + '"' : sql;
    sql = (reqData.status) ? sql + ' AND status = "' + reqData.status + '"' : sql;
    ............    

    /* ----- end of changes for filter ----- */


    /* ----- started changes for pagination ----- */

    sql = (!reqData.orderColumn || !reqData.orderBy) ? sql + ' ORDER BY pkId DESC' : sql+ ' ORDER BY ' + reqData.orderColumn + ' ' + reqData.orderBy;

    var start = (reqData.start) ? reqData.start : 0;
    var length = (reqData.length) ? reqData.length : 10;

    /* ----- end of changes for pagination ----- */



    mysql.conn.query(sql, (err, rows) => {
        if(err) {
            res.json({'status': 1, 'data': [], 'message': 'No result found'});
        }
        var len = rows.length;
        if(len) {
            sql += ' LIMIT ' + start + ',' + length;
            mysql.conn.query(sql, (err, rows1) => {
                if (!err) {
                    res.json({'status': 0, 'data': rows1, 'recordsTotal': len, 'recordsFiltered': len, 'start': start, 'draw': 1});
                } else {
                    res.json({'status': 1, 'data': [], 'message': 'No result found'});
                }
            });
        } else res.json({'status': 1, 'data': [], 'message': 'No result found'});
    });
}
0
votes

I have tried this in angular 7 and it worked.. runtime datatable changed

.Ts file

    import { Component, AfterViewInit, OnDestroy, OnInit, ViewChild } from '@angular/core';
    import { DataTableDirective } from 'angular-datatables';
    
    @Component({
      selector: 'app-selector',
      templateUrl: 'app-selector.component.html'
    })
    export class CustomRangeSearchComponent implements AfterViewInit, OnDestroy, OnInit {
      @ViewChild(DataTableDirective, {static: false})
      datatableElement: DataTableDirective;
      dtOptions: DataTables.Settings = {};
      tableData = [];
    
      ngOnInit(): void {
        this.dtOptions = {
          destroy: true,
          ordering: true,
          pagelength: 10,
          pagingType: "full_numbers",
          columnDefs: [{ 
            targets: 0,
            checkboxes:{
            selectRow: true,
            selected: true
          }]
        };
      }
    
      ngOnDestroy(): void {
        $.fn['dataTable'].ext.search.pop();
      }

      ngAfterViewInit(): void {
        this.dtTrigger.next();
      }
    
      getdata(){
    
        //... get your response
        this.tableData = response; //this should be in array

        setTimeout(() => {
          this.datatableElement.dtInstance.then((dtInstance: DataTables.Api) => {
            dtInstance.draw();
          });
        });
      }
    }

.HTML file

<button class="btn btn-primary" (click)="getData()">Filter by ID</button>
<table datatable [dtOptions]="dtOptions" class="row-border hover"></table>
0
votes

i have removed this below function and it worked for me. please follow below steps

  1. in you angular project go to this location 'node_modules\datatables.net\js'.
  2. there you can see one js file called 'jquery.datatable.js' file.

enter image description here

  1. open file and search term '_fnLog' . the _fnLog is a function.
  2. just comment _fnLog function whole code and save your file. your issue will be solved. enter image description here
0
votes

I had a similar issue and the only thing I needed to add is:

  ngAfterViewInit() {
    this.dtTrigger.next();
  }

As in the constructor I had:

this.options = {
  multiple: true,
};

In the Html declaration:

<table aria-describedby="Some interesting description" datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger"
<tbody>
<tr *ngFor="let item of data">
 <td>{{ item }}</td>
</tr>
</tbody> 
</table>

In the method that will get the data:

  someDataMethod(): void {
     this.dataAjaxService.someMethod(id).subscribe((data: any) => {
        this.data = data;
      }, error => {
        //handle error
      });
 }
0
votes

It' Easy.

onDestroy(){
  this.dtElements.forEach((dtElement: DataTableDirective,index:number) => {
    dtElement.dtInstance.then((dtInstance: any) => {       
        dtInstance.destroy();  // Before destroy
        this.dtTrigger.next(); // Again trigger of method. 
               });
    });
}

dtOptions:

this.dtOptions["new"] = {
      paging: true,
      fixedColumns: true,
      order: [[1, "asc"]],
      autoWidth: true,
      language: {
        "url": "assets/json/Turkish.json"
      },
      select: false,
      responsive: true,
      pagingType: 'full_numbers',
      pageLength: 10, 
      retrieve:true, **This is important**                                };

HTML

<table datatable [dtOptions]="dtOptions['new']" [dtTrigger]="dtTrigger" class="row-border hover fixed_header"
              style="width:100%">
<table datatable [dtOptions]="dtOptions['new']" [dtTrigger]="dtTrigger2" class="row-border hover fixed_header"
              style="width:100%">

The biggest battle is the war against ignorance.!