首页 > 解决方案 > 嵌套在 mat-tab 中的组件是否有生命周期挂钩?

问题描述

制表机新手。

我有一个 mat-tab-group 用于在三个 Tabulator 表中导航。

我使用的方法是在component.ts 中创建一个div 元素,并将其插入到component.html 中的现有div 中。

我遇到的问题是只有选定的选项卡将其 html 加载到 DOM 中,因此未选定选项卡中的任何 div 元素都不在 DOM 中,并且不能通过 id 引用到我的 component.ts 中。当我切换到最初加载的选项卡以外的选项卡时,不会绘制制表符表。

希望 Angular 有一个生命周期钩子,当用户选择该选项卡时,可以在 mat-tab 的子组件上调用它来触发绘制。

当然,我对其他/更好的方法持开放态度。

mat-tab-group html

<mat-tab-group *ngIf="hasData" mat-align-tabs="start">
    <mat-tab *ngFor="let tablename of tableNames">
        <ng-template matTabLabel>
            <span>{{tablename}}</span>
        </ng-template>
        <div>
            <app-tabulator-table *ngIf="dataServiceSelectedDate" [integrationName]="integrationName" [tableName]="tablename" [processDate]=dataServiceSelectedDate>
            </app-tabulator-table>
        </div>
    </mat-tab>
</mat-tab-group>

tablulator-table.component.ts

export class TabulatorTableComponent implements OnInit {

  @Input() tableName: string;
  @Input() processDate: string;
  @Input() integrationName: string;

  fields: RunDataTableField[];
  dataContent: RunDataContent;

  tab = document.createElement("div");
  tabColumns: any[] = [];
  tabRows: any[] = [];

  constructor(private clientDataService: ClientDataService) {
  }

  ngOnInit() {
    this.clientDataService.getRunDataContent(this.integrationName, this.processDate, `${this.tableName}.json`).toPromise().then(dataContent => 
      {
        console.log(this.dataContent)
        this.tabColumns = this.buildHeaders(dataContent);
        this.tabRows = this.buildRows(dataContent);
        this.redraw();
      });
  }

  calculationFormatter = function (cell, formatterParams) {
    var value = cell.getValue();
    cell.getElement().style.backgroundColor = "#fdd0ff";
    return value;
  }

  buildHeaders(runData: RunDataContent): any[] {
    console.log(`${this.tableName}: creating headers object`);
    var headers: any[] = [];
    runData.schema.fields.forEach(f => {
      var c: any = {};
      c.title = f.name;
      c.field = f.name;
      c.headerFilter = "input"
      switch (f.validationType) {
        case "calculation": {
          c.formatter = this.calculationFormatter
          break;
        }
        case "raw": {

        }
        case "table": {

        }

        default: {
          break;
        }
      }
      if (f.tip != null && f.tip.length > 0) {
        c.tooltip = f.tip;
        c.headerTooltip = f.tip;
      }
      headers = headers.concat(c);
    });
    console.log(`${this.tableName}: createad headers object`);
    console.log(this.tabColumns);
    return headers;
  }

  buildRows(runData: RunDataContent): any[] {
    console.log(`${this.tableName}: creating rows object`);
    var rows: any[] = [];
    runData.rows.forEach(f => {
      rows = this.tabRows.concat(f);
    });
    return rows;
  }



  private drawTable(): void {
    new Tabulator(this.tab, {
      layout: "fitDataStretch",
      selectable: true,
      selectableRangeMode: "click",
      data: [],
      columns: this.tabColumns,
      height: "311px"
    });
    document.getElementById(`${this.tableName}`).appendChild(this.tab);

    new Tabulator()
  }

  redraw() {
    console.log(`${this.tableName}: drawing table`)
    this.drawTable();
    console.log(`${this.tableName}: completed drawing table`)
  }
}

标签: javascriptangulartypescriptangular-materialtabulator

解决方案


根据 Angular Material Docs默认情况下,标签内容是急切加载的。急切加载的选项卡将初始化子组件,但在激活选项卡之前不会将它们注入 DOM。如果 tab 包含多个复杂的子组件或者 tab 的内容在初始化时依赖 DOM 计算,建议延迟加载 tab 的内容。通过在具有 matTabContent 属性的 ng-template 中声明正文,可以延迟加载选项卡内容。

因此,正确的方法是将 ng-template 与 matTabContent 一起使用。请找到以下代码以供参考:

<mat-tab *ngFor="let table of tableNames" [label]="table"> 
        <ng-template matTabContent>
           <div>
              <app-tabulator-table *ngIf="dataServiceSelectedDate" 
                [integrationName]="integrationName" [tableName]="tablename" 
                [processDate]=dataServiceSelectedDate>
              </app-tabulator-table>
           </div>

        </ng-template>
</mat-tab>

推荐阅读