繁体   English   中英

仅在从REST API接收数据后,我应该如何使用分页呈现Angular MatTable?

[英]How should I render a Angular MatTable with pagination only after data is received from a REST API?

我正在尝试创建一个表组件,用户可以在其中添加要加载到数据中的REST端点。 数据应该是一个任意对象的数组,因此这里不一定有可能没有严格的模式。

问题是我无法获取表,并且在我在REST端点上发出请求之前等待呈现的是paginator。 我有一个版本可以使分页工作,但是在加载数据之前,paginator(和空表)仍然出现。

我尝试过使用AfterViewChecked,以及初始化paginator和table的各种不同的地方。

Stackblitz样本在这里。 请注意,您不必在模态中输入有效的端点,因为它是从虚拟端点获取的。 我将模态尽可能接近我的默认状态。

component.ts文件:

import { Component, OnInit, ViewChild } from '@angular/core';
import { MatPaginator, MatTable, MatTableDataSource } from '@angular/material';
import { DomSanitizer } from '@angular/platform-browser';
import { RestService } from '../rest.service';

@Component({
    providers: [RestService],
    selector: 'table-widget',
    styleUrls: ['./table-widget.component.scss'],
    templateUrl: './table-widget.component.html',
})

export class TableWidgetComponent implements OnInit {
    public dataSource: MatTableDataSource<any> = new MatTableDataSource();
    // map of header names (which are keys in series) to whether they should be visible
    public headers: Map<string, boolean>;
    public headerKeys: string[];

    @ViewChild(MatTable) private table: MatTable<any>;
    @ViewChild(MatPaginator) private paginator: MatPaginator;

    // array of header titles, to get arround ExpressionChangedAfterItHasBeenCheckedError
    private restEndpoint: string;
    private editModalVisibility: boolean;

    constructor(private restService: RestService, private sanitizer: DomSanitizer) { }

    // called each time an AppComponent is initialized
    public ngOnInit(): void {
        this.headers = new Map<string, boolean>();
        this.editModalVisibility = false;
        this.dataSource.paginator = this.paginator;
    }

    public eventFromChild(data: string): void {
        this.restEndpoint = data;
        // return value of rest call
        this.restService.getFromEndpoint(this.restEndpoint)
            .subscribe((series) => {
                this.dataSource.data = series;
                this.table.renderRows();

                // set keys, unless series is empty
                if (series.length > 0) {
                    Object.keys(this.dataSource.data[0]).forEach((value) => {
                        this.headers.set(value, true);
                    });
                }
                this.headerKeys = Array.from(this.headers.keys());
            });
    }
    .
    .
    .
}

和HTML文件:

<div [ngClass]="['table-widget-container', 'basic-container']">
  <div [ngClass]="['table-container']">
    <mat-table [ngClass]="['mat-elevation-z8']" [dataSource]="dataSource">
      <ng-container *ngFor="let header of getVisibleHeaders()" matColumnDef={{header}}>
        <mat-header-cell *matHeaderCellDef> {{header | titlecase}} </mat-header-cell>
        <mat-cell *matCellDef="let entry"> {{entry[header]}} </mat-cell>
      </ng-container>

      <mat-header-row *matHeaderRowDef="getVisibleHeaders()"></mat-header-row>
      <mat-row *matRowDef="let row; columns: getVisibleHeaders();"></mat-row>
    </mat-table>

    <mat-paginator #paginator [pageSize]="5" [pageSizeOptions]="[5, 11, 20]"></mat-paginator>

  </div>
  <button *ngIf="dataSource.data.length" (click)="openModal()" class="add-rest-button">
    Edit Table
  </button>
  <add-rest-button (sendDataToParent)="eventFromChild($event)"></add-rest-button>
</div>

当我尝试将*ngIf="dataSource.data.length"mat-tablemat-paginator ,显示的是paginator但是没有“链接”到表,或者表中没有数据,并且我得到以下错误:

TypeError: Cannot read property 'renderRows' of undefined

我知道发生此错误是因为由于ngIf指令而未定义表,但我不确定如何有效地隐藏表。

将属性添加到组件isInitialized

将您的方法更新为:

public eventFromChild(data: string): void {
        console.log(this.dataSource.data.length);
        this.restEndpoint = data;
        // TODO: handle errors of restService
        // return value of rest call
        this.restService.getFromEndpoint(this.restEndpoint)
            .subscribe((series) => {
               this.isInitialized = true;
               ...
             }

和你的HTML:

<div *ngIf="isInitialized" [ngClass]="['table-widget-container', 'basic-container']">
.
.
.
</div>

我找到了解决这个问题的方法,但我不会说它解决了根本问题; 在数据准备好之前,只需隐藏表和分页器的容器。

首先,我将HTML中的第2行更改为:

<div [ngClass]="['table-container']" [style.display]="getTableVisibleStyle()">

然后我将以下函数添加到TS文件中:

    public getTableVisibleStyle() {
        let style: string = 'none';
        if (this.tableVisibility) {
            style = 'block';
        }
        // have to do this to get past overzealous security
        return this.sanitizer.bypassSecurityTrustStyle(style);
    }

其中tableVisibility是在tableVisibility中设置为false的布尔值,然后在更新数据时更改为true

它确实工作得很好,虽然看起来很hacky而且不是特别健壮。 如果我发现一种更好的方法,我可能会在以后重新审视这个问题。

您可以执行以下操作来完成此操作。

不要初始化dataSource变量。

public dataSource: MatTableDataSource<any>;

table-container你可以*ngIf="dataSource"

<div [ngClass]="['table-container']" *ngIf="dataSource">

然后在收到数据时初始化变量。

this.dataSource = new MatTableDataSource();
this.dataSource.data = series;
this.table.renderRows();

要再次隐藏它,请将变量null

this.dataSource = null;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM