使用 Angular 数据表作为共享组件时出现的问题

Issues when using Angular Datatables as a shared component

我将数据表用作一个组件,这样我就可以在我拥有的所有模板中使用它。我有以下文件:

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();
      }
}

模板文件table.component.html如下所示:

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

我正在使用这个组件,如下所示:

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

现在我面临着多个问题:

  1. 有时显示No data available in table,但当 页面刷新了,就没了

  2. 有时显示 DataTables warning: table id=releaseDatatable - Cannot reinitialise DataTable. For more information about this error, please see http://datatables.net/tn/3"

如果有人能帮我解决这个问题,那将非常有帮助。我正在使用 Angular Datatables 包。

好像是两个不同的问题;

第二个错误DataTables warning: table id=releaseDatatable - Cannot reinitialise DataTable表示您使用了多个具有相同id的dataTable。 当您加载多个 dataTable 组件时,很可能会遇到此错误。

要解决这个问题,您应该生成一种识别每个唯一数据的方法 table 例如,声明一个变量计数器并在获取数据表时调用 $('#releaseDatatable' + counter).DataTable().destroy();,同时绑定到 [attr.id]='"releaseDatatable" + counter' html

第一个错误将归因于下面的代码

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

考虑上面的问题 2,您在其中加载具有相同 ID 的相同 HTMLElement。在你销毁元素然后调用 this.dtTrigger.next(); 没有元素将存在因此错误 No data available in table

为数据表设置唯一 ID 应该可以解决这两个问题