Как я должен рендерить Angular MatTable с нумерацией страниц только после получения данных от REST API? - PullRequest
0 голосов
/ 02 апреля 2019

Я пытаюсь создать компонент таблицы, в который пользователь может добавить конечную точку REST для загрузки в данные.Предполагается, что данные будут массивом произвольных объектов, поэтому здесь не обязательно возможна строгая схема.

Проблема в том, что я не могу получить таблицу и ее paginator, чтобы ждать рендеринга до тех пор, пока я не сделаю запросна конечной точке REST.У меня есть версия, которая работает с разбивкой по страницам, но перед загрузкой данных по-прежнему появляются страницы (и пустая таблица).

Я пытался использовать AfterViewChecked, а также различные места инициализации paginator иТаблица.

Образец 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-table и mat-paginator, либо отображается страница, но не «привязана» к таблице, либо таблица отображается без данных, и я получаю следующую ошибку:

TypeError: Cannot read property 'renderRows' of undefined

Я понимаю, что эта ошибка возникает из-за того, что таблица не определена из-за директивы ngIf, но я не уверен, как иначе эффективно скрыть таблицу.

Ответы [ 3 ]

0 голосов
/ 03 апреля 2019

Я нашел способ решения этой проблемы, но я бы не сказал, что он решает основную проблему;просто скройте контейнер для таблицы и paginator до того, как данные будут готовы.

Сначала я изменил строку 2 в HTML на следующее:

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

Затем я добавил следующую функцию в TSfile:

    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 - это логическое значение, установленное в false в ngOnInit, затем изменяется на true при каждом обновлении данных.

Это работает довольно хорошо,хотя это кажется хакерским и не особенно надежным.Я могу вернуться к этому позже, если найду лучший способ сделать это.

0 голосов
/ 08 апреля 2019

Для этого вы можете сделать следующее.

Не инициализируйте переменную 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;
0 голосов
/ 02 апреля 2019

Добавьте свойство к вашему компоненту 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>
...