问题
I've seen similar questions, but nothing seems to work for me. I have a mat table where I display data from an api. But I don't know how to iterate through the 'dataSource'. Below is my code, and how I get the data when I check console log. ts file
import {AfterViewInit, Component, OnInit, ViewChild} from '@angular/core';
import {Pokemon, PokemonData} from '../../models/pokemon';
import {PokemonService} from '../../models/services/pokemon.service';
import {ActivatedRoute} from '@angular/router';
import {MatTableDataSource} from '@angular/material/table';
import {MatPaginator} from '@angular/material/paginator';
@Component({
selector: 'app-pokemon',
templateUrl: './pokemon.component.html',
styleUrls: ['./pokemon.component.css']
})
export class PokemonComponent implements OnInit {
public pokemon: Pokemon[];
public name: string;
public url: string;
public type: string;
expandedElement: PokemonData | null;
dataSource = new MatTableDataSource();
displayPokemonColumns: string[] = ['name', 'url', 'pokemonDetails'];
@ViewChild(MatPaginator, {read: true}) paginator: MatPaginator;
//
// // tslint:disable-next-line:typedef
// tslint:disable-next-line:typedef
// ngAfterViewInit() {
// // this.dataSource.paginator = this.paginator;
// //
// }
constructor(private pokemonService: PokemonService, private route: ActivatedRoute) {
}
// function (which is called below)issues call to API. subscribes shows to the results that are returned. adds results to shows array
onLoadPokemonList(): void {
this.pokemonService.getPokemonList().subscribe(
res => {
// this.pokemon = JSON.parse(JSON.stringify(res));
this.pokemon = res;
this.dataSource.data = this.pokemon;
setTimeout(() => {
this.dataSource.paginator = this.paginator;
});
console.log(this.dataSource);
});
}
ngOnInit(): void {
this.onLoadPokemonList();
}
}
html file
<div class="table" *ngIf="pokemon">
<h1 matColumnDef="title">POKEDEX</h1>
<table mat-table #table [dataSource]="dataSource" class="mat-elevation-z8" multiTemplateDataRows>
<!-- <table mat-table [dataSource]="pokemon.results" class="mat-elevation-z8" multiTemplateDataRows>-->
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<!-- <td mat-cell *matCellDef="let res"> {{res?.name}} </td>-->
<td mat-cell *matCellDef="let res"> {{res.name}} </td>
</ng-container>
<ng-container matColumnDef="url">
<th mat-header-cell *matHeaderCellDef> URL </th>
<td mat-cell *matCellDef="let res"> {{res.url}} </td>
</ng-container>
<ng-container matColumnDef="pokemonDetails">
<th mat-header-cell *matHeaderCellDef> Pokemon Details </th>
<td mat-cell *matCellDef="let res">
<button mat-raised-button color="primary" routerLink="/pokemonData/{{res.name}}">Pokemon Details</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayPokemonColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayPokemonColumns;"
class="example-element-row"
[class.example-expanded-row]="expandedElement === row"
(click)="expandedElement = expandedElement === row ? null : row"></tr>
</table>
<mat-paginator #paginator
[pageSize]="10"
[pageSizeOptions]="[5, 10, 20]">
</mat-paginator>
</div>
this is the data I get back:
MatTableDataSource {_renderData: BehaviorSubject, _filter: BehaviorSubject, _internalPageChanges: Subject, _renderChangesSubscription: Subscriber, sortingDataAccessor: ƒ, …}filterPredicate: (data, filter) => {…}filteredData: {count: 1050, next: "https://pokeapi.co/api/v2/pokemon?offset=150&limit=150", previous: null, results: Array(150)}sortData: (data, sort) => {…}sortingDataAccessor: (data, sortHeaderId) => {…}_data: BehaviorSubject {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}_filter: BehaviorSubject {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}_internalPageChanges: Subject {_isScalar: false, observers: Array(0), closed: false, isStopped: false, hasError: false, …}_paginator: undefined_renderChangesSubscription: Subscriber {closed: false, _parentOrParents: null, _subscriptions: Array(1), syncErrorValue: null, syncErrorThrown: false, …}_renderData: BehaviorSubject {_isScalar: false, observers: Array(1), closed: false, isStopped: false, hasError: false, …}data: (...)filter: (...)paginator: (...)sort: (...)__proto__: DataSource
The data I need is under filteredData.
When I do
<table mat-table [dataSource]="pokemon.results" class="mat-elevation-z8" multiTemplateDataRows>
instead of dataSource, I get the correct table, but the paginator (obviously) doesn't work.
回答1:
The problem is tha,t when you try to assing the paginator, the paginator is not in the DOM (you has the mat-paginator under a div that has a *ngIf). You need give a "change" to Angular to get it, so you need enclosed in a setTimeout inside subscribe function
this.pokemonService.getPokemonList().subscribe(res => {
//why you use JSON.stringify? in Angular by defect a http.get return a json
this.pokemon = JSON.parse(JSON.stringify(res));
// this.pokemon = res;
this.dataSource.data = this.pokemon;
//here you indicate the paginator
setTimeout(()=>{
this.dataSource.paginator = this.paginator;
})
});
Brief explain: your variable "pokemon" is null or undefined until you subscribe and get the data. (rememeber that you has *ngIf="pokemon"
in html). when you get the data, the variable has value, so, "when Angular finished the instructions", refresh the app to show the table. this is the reason because you need a setTimeout
回答2:
what worked in the end, was removing the *ngIf condition on the template. I found this solution on stack overflow. Paginator now works fine.
来源:https://stackoverflow.com/questions/64010053/mat-paginator-of-mat-tabledoesnt-work-with-api-data