1

I am using the Datatable as a component so that I can use it in all the templates I have. I have the following files :

table.component.ts

import * as _ from "lodash";
import { Observable, Subject, merge } from 'rxjs';
import { Component, OnInit, ViewChild, Renderer2, Input, Output, EventEmitter, ContentChild, ElementRef } from "@angular/core";

import { DataTableDirective } from "angular-datatables";
import { TableActionEvent } from "../../types/table/table.actions";

@Component({
    selector: "common-table",
    templateUrl: "./table.component.html",
    styleUrls: ["./table.component.scss"],
})
export class TableComponent implements OnInit {

    public dtOptions: DataTables.Settings = {};
    public dtTrigger: Subject<any> = new Subject();
    public _data: Array<any>;
    public _settings: any;
    public _loading: boolean;

    @ViewChild(DataTableDirective, { static: false }) private datatableElement: DataTableDirective;

    /**
    *  Grid data with pagination meta
    */

    @Input()

    set data(data: any) {
        if (data) {
            this._data = data;
        }
    }

    get data(): any {
        return this._data;
    }

    /**
    *  Grid data with pagination meta
    */

    @Input()

    set settings(data: any) {
        if (data) {
            this._settings = data;
        }
    }

    get settings(): any {
        return this._settings;
    }

    @Input()

    set loading(loading: boolean) {
        this._loading = loading;
        setTimeout(() => {
            $('#releaseDatatable').DataTable().destroy();
            this.dtTrigger.next();
        }, 100);
    }

    get loading(): boolean {
        return this._loading;
    }


    @Output() public event: EventEmitter<TableActionEvent<any>> = new EventEmitter<TableActionEvent<any>>();

    /**
     * DashboardComponent constructor
     */
    constructor(
        private renderer: Renderer2,
        private elem: ElementRef
    ) { }

    /**
     * @memberof DashboardComponent
     */
    public ngOnInit(): void {
        this.dtOptions = {
            info: false,
            order: []
        };
    }

    /**
     *
    */
    cellRender(render, row) {
        if (_.isString(render)) {
            return render;
        }

        if (_.isFunction(render)) {
            return render(row);
        }
    }
   
    /**
     * @param $event
     */
    public search($event) {
        const term = $event.target.value;
        this.datatableElement.dtInstance.then((dtInstance: DataTables.Api) => {
            dtInstance.search(term).draw();
        });
    }

    /**
   * On Table Action
   *
   * @param {string} action
   * @param {T} row
   * @param {number} index
   *
   * @memberof AdminGridComponent
   */
    public onAction(action: string, row: any): void {
        const tableActionItem: any = {
            action: action,
            row: row
        };

        this.event.emit(tableActionItem);
    }

    rerender() {
        this.datatableElement.dtInstance.then((dtInstance: DataTables.Api) => {
            dtInstance.destroy();
            this.dtTrigger.next();
        });
    }

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

and the template file table.component.html is like the following:

<div class="ma-datatables">
    <form>
        <div class="d-flex align-items-center app-login_input-layout">
            <input class="form-control app-login_input-style rm-release_search-bar" type="search" id="release-search"
                placeholder="Search here..." (keyup)=search($event)>
            <i class="material-icons rm-release_search-icon">search</i>
        </div>
    </form>
    <div class="table-responsive">
        <div *ngIf="!loading">
            <table class="table animate__animated animate__fadeIn" id="releaseDatatable" datatable
                [dtOptions]="dtOptions" [dtTrigger]="dtTrigger">
                <thead>
                    <tr>
                        <th *ngFor="let header of settings.columns">{{ header.title }}</th>
                        <th *ngIf="settings.actions">Actions</th>
                    </tr>
                </thead>
                <tbody>
                    <tr *ngFor="let release of data">
                        <ng-container *ngFor="let column of settings.columns">
                            <td class="rm-release_table-cell" [style.width]=column.width>
                                <div>
                                    <p *ngIf="column.dataType !='html'" class="rm-release_data-id">
                                        {{release[column.field]}}
                                    </p>
                                    <span *ngIf="column.dataType =='html'">
                                        <div innerHTML="{{ cellRender(column.render, release) }}"></div>
                                    </span>
                                </div>
                            </td>
                        </ng-container>
                        <td class="rm-release_table-cell" *ngIf="settings.actions">
                            <div>
                                <a id="release-action" href="javascript:void(0)" (click)="openAction($event)">
                                    <i class="material-icons">more_vert</i>
                                </a>
                                <div class="rm-release_action-layout hidden" #actionSlide
                                    id="release-{{release[settings.columns[0].field]}}">
                                    <div class="rm-release_action-container animate__animated" #actionContainer>
                                        <div
                                            class="d-flex align-items-center justify-content-between rm-release_action-header">
                                            <a class="rm-release_action-close" href="javascript:void(0)"
                                                (click)="closeAction($event)">
                                                <i class="material-icons">close</i>
                                            </a>
                                        </div>
                                        <div class="rm-release_action-item-layout">
                                            <div class="rm-release_action-item-layout">
                                                <ng-container *ngIf="release.permitted_actions;else actionMenu">
                                                    <ng-container *ngFor="let action of settings.actions">
                                                        <div *ngIf="release.permitted_actions.includes(action.action)"
                                                            class="d-flex align-items-center rm-release_action-item"
                                                            (click)="onAction(action.action, release)">
                                                            <i class="material-icons">{{action.icon}}</i>
                                                            <p>{{action.title}}</p>
                                                        </div>
                                                    </ng-container>
                                                </ng-container>
                                                <ng-template #actionMenu>
                                                    <ng-container *ngFor="let action of settings.actions">
                                                        <div class="d-flex align-items-center rm-release_action-item"
                                                            (click)="onAction(action.action, release)">
                                                            <i class="material-icons">{{action.icon}}</i>
                                                            <p>{{action.title}}</p>
                                                        </div>
                                                    </ng-container>
                                                </ng-template>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </td>
                    </tr>
                </tbody>
            </table>
        </div>

    </div>
</div>

and I am using this component as shown below:

  <common-table [data]="items" [settings]="settings" [loading]="isLoading"
      (event)="onGridEvent($event)">
  </common-table>

Now I am facing multiple issues here :

  1. It is showing No data available in table sometimes, but when the page is refreshed, it will be gone.

  2. Sometimes, it is showing DataTables warning: table id=releaseDatatable - Cannot reinitialise DataTable. For more information about this error, please see http://datatables.net/tn/3"

It will be very much helpful if someone can help me to fix this issues. I am using the Angular Datatables package.

1
  • 1
    Please make a plunker in order to reproduce the problem. Commented Sep 2, 2020 at 6:57

1 Answer 1

2
+200

There seems to be two different problems;

The second error DataTables warning: table id=releaseDatatable - Cannot reinitialise DataTable indicates that you are using more than one dataTable with the same id. This error is most likely being experienced when you load more than one dataTable component.

To solve this you should generate a way of identifying each unique data table eg declare a variable counter and call $('#releaseDatatable' + counter).DataTable().destroy(); when getting then dataTable while binding to [attr.id]='"releaseDatatable" + counter' in the html

The First error will be attributed to the code below

  $('#releaseDatatable').DataTable().destroy();
  this.dtTrigger.next();

Consider the problem 2 above where you were loading the same HTMLElement with the same id. after you destroy the element then call the this.dtTrigger.next(); no Elements would be existing hence the error No data available in table

Setting unique ids for the dataTable should solve both problems

Sign up to request clarification or add additional context in comments.

2 Comments

Actually this has fixed the issues. I haven't realized I am using the same ID multiple times. Now I have removed the ID and it is automatically assigning separate ids each time. Thanks for the solution.
Glad it helped!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.