Reputation: 700
We initialise MatPaginator in our components
like
@ViewChild(MatPaginator) paginator: MatPaginator;
and assign to a MatTable DataSource
defined in our component as
matTableDataSource.paginator = this.paginator;
This doesn't work in a use case when the data source is initialised asynchronously using async
pipe with a combination of *ngIf
. As,
<div *ngIf="someDataObs | async as yourData else loading">
<mat-table #table [dataSource]="yourData">
... your headers and columns
</mat-table>
<mat-paginator [pageSize]="10" showFirstLastButtons></mat-paginator>
</div>
Note: you could put mat-paginator
below the div
with *ngIf
, but that's not an ideal solution, more so if you need to show multiple tables in a same component coming with a single backend asynchronous call.
Since the mat-paginator
will get initialised asynchronously, using a code such as below will not work as paginator
will be null
.
ngAfterViewInit() {
this.someDataObs = this.backendService.get()
.map(value => {
const matTableDataSource = new MatTableDataSource<SomeType>(value);
matTableDataSource.paginator = this.paginator; // will be null here
return matTableDataSource;
});
}
To have a way for this to work would've required MatPaginator
to have an output property
to emit once initialised, but that doesn't exist for now.
Use of async
pipe and *ngIf
makes the code really concise and you should not avoid it to overcome this use case.
Any solution to achieve this would be helpful.
Upvotes: 3
Views: 2950
Reputation: 774
There is another solution on GitHub:
Just add this HIDDEN before the table While HIDDEN==TRUE the table will not be rendered before the dataSource is loaded:
<div [hidden]="isLoading">
<mat-table [dataSource]="dataSource">
...
</mat-table>
</div>
Upvotes: 0
Reputation: 774
I tested this Github issue solution and it works fine
Just add this *ngIf="pagination" to your mat-paginator in HTML:
<table mat-table [dataSource]="dataSource">
<!-- Position Column -->
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef> No. </th>
<td mat-cell *matCellDef="let element"> {{element.position}} </td>
</ng-container>
......
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons
*ngIf="pagination" > <!-- THIS!!! -->
</mat-paginator>
And then add this estructure to your component
export class TableComponent implements OnInit {
@Input('pagination') pagination: boolean;
@ViewChild(MatPaginator, {static: false}) set matPaginator(paginator:
MatPaginator) {
if (this.pagination) {
this.dataSource.paginator = paginator;
}
}
displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
dataSource = new MatTableDataSource<PeriodicElement>(ELEMENT_DATA);
....
}
Upvotes: 0
Reputation: 81
I just had the same problem.This is a known problem and they have solved this, in my opinion, better.
@ViewChild(MatPaginator) set matPaginator( paginator: MatPaginator){
this.dataSource.paginator = paginator;
}
@ViewChild(MatSort) set matSort( sort: MatSort){
this.dataSource.sort = sort;
}
https://github.com/angular/material2/issues/10205#issuecomment-465455599
Upvotes: 1
Reputation: 6821
Endeed, your problem is the *ngIf.
With @ViewChild(MatPaginator) paginator: MatPaginator
, when paginator is requested, it is not found in the DOM and it return null.
A solution to this problem, is to replace your *ngIf by a statement with display:none
. So the paginator will stay in the DOM.
Upvotes: 0