Angular 9.1.0。 "mat-table" 不会从 GET Rest 加载数据源 Api

Angular 9.1.0. "mat-table" won't load dataSource from GET Rest Api

我试图将数据加载到 mat-table,但是当我 console.log 我试图加载的数据源时,它说数据未定义。

Link To Image Of Problem

我检索到的对象是嵌套的。 API Request

我正在学习 Angular 网站的官方教程,它是 material table examples。 也可以从这里访问 Table retrieving data through HTTP

回复:

{"BTC":{"USD":8682.55,"EUR":7851.55},"ETH":{"USD":224.8,"EUR":203.77}}

这是我目前的尝试: (您会注意到,未使用 ngAfterViewInit(),这是由于用户输入 Api 必须等待,我仍在修改它)。

HTML:

<button (click)="removeList()">Reset</button>
<button (click)="initialiseTableData()">Display Value</button>


<div class="example-container mat-elevation-z8">
  <div class="example-loading-shade" *ngIf="isLoadingResults">
    <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
  </div>
  <mat-table #table [dataSource]="dataSource" class="example-table" matSort matSortActive="created" matSortDisableClear
    matSortDirection="asc">

    <ng-container matColumnDef="cryptocurrency">
      <mat-header-cell *matHeaderCellDef>Cryptocurrency</mat-header-cell>
      <mat-cell *matCellDef="let row">{{ row.items.cryptovalue }}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="currency">
      <mat-header-cell *matHeaderCellDef>Currency</mat-header-cell>
      <mat-cell *matCellDef="let row">{{ row.items.currency }}</mat-cell>
    </ng-container>

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

  <mat-paginator [length]="resultsLength" [pageSize]="30">
  </mat-paginator>
</div>

这是我的 .ts :

import { Component, OnInit, AfterViewInit, ViewChild } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { merge, Observable, of as observableOf } from 'rxjs';
import { catchError, map, startWith, switchMap } from 'rxjs/operators';
import { FormControl } from '@angular/forms';
import { MatSortModule, MatSort } from '@angular/material/sort';
import { MatPaginatorModule, MatPaginator } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';


export interface TableDataApi {
  items: Tabledata[];
  total_count: number;
}

export interface Tabledata {
  cryptovalue: {
    currency: string;
  };
}

@Component({
  selector: 'app-crypto-chooser',
  templateUrl: './crypto-chooser.component.html',
  styleUrls: ['./crypto-chooser.component.css']
})

export class CryptoChooserComponent implements OnInit, AfterViewInit {

  constructor(private client: HttpClient) { }

  displayedColumns = ['cryptocurrency', 'currency'];
  dataSource = new MatTableDataSource();
  resultsLength = 0;
  isLoadingResults = false;

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  initialiseTableData() {
    this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);

    merge(this.sort.sortChange, this.paginator.page)
      .pipe(
        startWith({}),
        switchMap(() => {
          this.isLoadingResults = true;
          return this.getCoins();
        }),
        map(data => {
          this.isLoadingResults = false;
          this.resultsLength = data.total_count;
          return data.items;
        }),
        catchError(() => {
          this.isLoadingResults = false;
          return observableOf([]);
        })
      ).subscribe(data => this.dataSource.data = data);
    console.log(this.dataSource);
  }

  ngAfterViewInit() {
  }

  getCoins(): Observable<TableDataApi> {
    this.generateUrl();
    return this.client.get<TableDataApi>(this.urlComplete, this.httpHeader);
  }

我阅读了一些关于 material table 数据源 API Angular Material API Table Docs 的文档,他们说了以下内容:

The table's source of data, which can be provided in three ways (in order of complexity):

Simple data array (each object represents one table row).

Stream that emits a data array each time the array changes.

DataSource object that implements the connect/disconnect interface.

您可以使用第一种方式(简单数据数组)。

尝试这样做以使用简单的数据数组而不是 matTableDataSource 对象。

// use simple array instead of new MatTableDataSource()
// and define your interface later, for the moments we will use any
dataSource: any[] = []; 

在这里你必须修改你的订阅方法,以便将响应分配给 dataSource 变量,现在它是一个简单的数组。

  initialiseTableData() {
    this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);

    merge(this.sort.sortChange, this.paginator.page)
      .pipe(
        startWith({}),
        switchMap(() => {
          this.isLoadingResults = true;
          return this.getCoins();
        }),
        map(data => {
          console.info('data is an object!', data);
          this.resultsLength = 0; // fix this later
          this.isLoadingResults = false;
          // here, data has total_count and items attributes?
          // this.resultsLength = data.total_count;
          // I think data is an object because you're getting
          // an object as response, you're not getting a TableDataApi
          // structure
          return data;
        }),
        catchError(() => {
          this.isLoadingResults = false;
          return observableOf([]);
        })
      ).subscribe(data => {
        // data is an object, is not an array
        // but your dataSource variable needs to be an array, so
        // you have to add data into [] in order to create an array
        // with your payload
        this.dataSource = [data]; // <- assign data to dataSource
        console.info('an array with my object', this.dataSource);
      });
  }

现在你添加了一个带有items和totalCount属性的接口,我不知道你为什么这样做,因为你的HTTP请求实际上有一个对象负载,也就是说: 这是你的有效载荷,它是一个对象。此对象没有 totalCount 或 items 属性。您需要修复界面。

您的数据负载是:

{"BTC":{"USD":8682.55,"EUR":7851.55},"ETH":{"USD":224.8,"EUR":203.77}}

我上面写的是把你的对象payload转成数组的方法,只把你的数据对象加到[].

删除接口并暂时使用 any,但稍后您需要定义具有正确结构的接口。

  getCoins(): Observable<any> { // define interface with your correct structure
    this.generateUrl();
    return this.client.get<any>(this.urlComplete, this.httpHeader);
  }