简体   繁体   English

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

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

I am attempting to create a table component where a user can add a REST endpoint to be loaded into the data. 我正在尝试创建一个表组件,用户可以在其中添加要加载到数据中的REST端点。 The data is expected to be an array of arbitrary objects, so no strict schema is necessarily possible here. 数据应该是一个任意对象的数组,因此这里不一定有可能没有严格的模式。

The issue is that I cannot get the table and it's paginator to wait to render until after I have made a request on the REST endpoint. 问题是我无法获取表,并且在我在REST端点上发出请求之前等待呈现的是paginator。 I have a version that gets the pagination working, but the paginator (and the empty table) still appear before data is loaded. 我有一个版本可以使分页工作,但是在加载数据之前,paginator(和空表)仍然出现。

I've tried using AfterViewChecked, as well as various different places of initializing the paginator and table. 我尝试过使用AfterViewChecked,以及初始化paginator和table的各种不同的地方。

Stackblitz sample here. Stackblitz样本在这里。 Note that you don't have to enter a valid endpoint in the modal, as it is fetching from a dummy one. 请注意,您不必在模态中输入有效的端点,因为它是从虚拟端点获取的。 I left the modal in as close to my default state as possible. 我将模态尽可能接近我的默认状态。

The component.ts file: 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());
            });
    }
    .
    .
    .
}

and the HTML file: 和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>

When I attempt to add an *ngIf="dataSource.data.length" to the mat-table and mat-paginator , either the paginator is shown but not "linked" to the table, or the table appears with no data, and I get the following error: 当我尝试将*ngIf="dataSource.data.length"mat-tablemat-paginator ,显示的是paginator但是没有“链接”到表,或者表中没有数据,并且我得到以下错误:

TypeError: Cannot read property 'renderRows' of undefined

I understand that this error is occurring because the table isn't defined because of the ngIf directive, but I'm not sure how to otherwise effectively hide the table. 我知道发生此错误是因为由于ngIf指令而未定义表,但我不确定如何有效地隐藏表。

Add a property to your component isInitialized 将属性添加到组件isInitialized

Update your method to: 将您的方法更新为:

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;
               ...
             }

and your html to: 和你的HTML:

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

I found a way of solving this problem, but I wouldn't say it addresses the root issue; 我找到了解决这个问题的方法,但我不会说它解决了根本问题; simply hide the container for the table and paginator before data is ready. 在数据准备好之前,只需隐藏表和分页器的容器。

First, I changed line 2 in the HTML to this: 首先,我将HTML中的第2行更改为:

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

Then I added the following function to the TS file: 然后我将以下函数添加到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);
    }

where tableVisibility is a boolean set to false in ngOnInit, then changed to true whenever the data is updated. 其中tableVisibility是在tableVisibility中设置为false的布尔值,然后在更新数据时更改为true

It does work fairly well, though it seems hacky and not particularly robust. 它确实工作得很好,虽然看起来很hacky而且不是特别健壮。 I may revisit this later if I discover a better way of doing this. 如果我发现一种更好的方法,我可能会在以后重新审视这个问题。

You could do the following to accomplish this. 您可以执行以下操作来完成此操作。

Don't initialize your dataSource variable. 不要初始化dataSource变量。

public dataSource: MatTableDataSource<any>;

On the table-container you can *ngIf="dataSource" table-container你可以*ngIf="dataSource"

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

Then initialize the variable when the data is received. 然后在收到数据时初始化变量。

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

To hide it again, null the variable 要再次隐藏它,请将变量null

this.dataSource = null;

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

相关问题 我希望我的组件在角度2中未从api接收不到数据时不渲染 - I want my component not to render if data is not received from api in angular 2 如何合并多个REST API JSON output并显示在MatTable Angular - How to combine multiple REST API JSON output and show in MatTable Angular 如何以角度显示从后端 api 接收到的数据 - how can i show the data received from backend api in angular Angular 材料数据表过滤和分页不适用于来自 rest 的数据 Api - Angular material dataTable Filtering and pagination not working with data from rest Api 如何使用Spring Boot在angular 4中的HTTP Get方法中传递分页对象以使用REST API从REST API中获取数据 - How to pass Pagination object in HTTP Get method in angular 4 for fetching data from REST API using spring boot 上传文件后如何刷新MatTable数据 - How to Refresh MatTable Data after upload file Angular - MatTable 不显示数据 - Angular - MatTable not displaying data 如何从获取的二进制数据中在前端Angular中显示pdf(二进制数据是从REST API接收对象的元素之一)? - How to display pdf in frontend Angular from fetched binary data ( Binary data is one the element of received an object from REST API)? 如何从api渲染Angular中的数据 - How to render data in Angular from api Angular - 如何使用 Wordpress 创建分页 REST ZDB974238714CA8DE634A7CE1D083A1 - Angular - How to create pagination with Wordpress REST API?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM