Search code examples
angularangular-material-table

How to implement pagination for dynamic inner datasource inside other mat-table?


I have a mat-table which is nested inside other mat-table. The datasource for the nested mat-table is an array of objects from first mat-table.

I want to bind a pagination for the inner dataSource: [dataSource]="element.users". How can I reach this? I have been searching here in SO and trying couple of options, but none of them did work. Any Idea, how to manage such use case?

Code - HTML:

<ng-container *ngFor="let el of adminsList">
 <table mat-table [dataSource]="myDataSource" multiTemplateDataRows ...>
    <ng-container matColumnDef="name">
          <th mat-header-cell *matHeaderCellDef>
              <div>{{el['version'] }}</div>
          </th>
          <td mat-cell *matCellDef="let element;">
              <table mat-table [dataSource]="element.users">
                 <ng-container matColumnDef="{{innerColumn}}" *ngFor="let innerColumn of columnsToDisplay">
                     <th mat-header-cell *matHeaderCellDef>
                        {{innerColumn }}
                     </th>
                     <td mat-cell *matCellDef="let element">
                        {{element[innerColumn]}}
                     </td>
                 </ng-container>
                 <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
                 <tr mat-row *matRowDef="let row; columns: columnsToDisplay"></tr>
              </table>
              <mat-paginator [pageSize]="5" [pageSizeOptions]="[5, 10, 20]"
                        showFirstLastButtons]="true" #innerPaginator>
              </mat-paginator>
          </td>
    </ng-container>
    <ng-container matColumnDef="deployedVersion">
        // display: none to hide the outer table column headers
        <th mat-header-cell *matHeaderCellDef style="display: none"></th>
        <td mat-cell *matCellDef="let element" style="display: none"></td>
    </ng-container>
    <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
    <tr mat-row *matRowDef="let element; columns: columnsToDisplay"></tr>
  </table>
</ng-container>

Code - TS:

@ViewChild('innerPaginator') innerPaginator: MatPaginator;
innerDataSourceObject: any;
...
...
this.userService.getUserInfo().subscribe((res: userData) => {
    ...
    this.innerDataSourceObject = new MatTableDataSource<EnvComponents>(res);
    ...
});
...
...
ngAfterViewInit() {
    this.innerDataSourceObject.innerPaginator.paginator = this.innerPaginator;
    ...
}

Solution

  • A mat-paginator can be use when the dataSource is a MatTableDataSource or "standalone". I imagine you element.users is an array, so you should use as "standalone"

    To use as standalone, is simple use slice pipe in your source

    As you use a template ReferenceVariable "innerPaginator" you can get the value of the innerPaginator.pageIndex (starts with 0) and innerPaginator.pageSize

    You need add the property length to the paginator (you can see the example in the docs)

          <td mat-cell *matCellDef="let element;">
              <table mat-table [dataSource]="element.users
                 |slice:(innerPaginator.pageIndex*innerPaginator.pageSize)
                       :((innerPaginator.pageIndex+1)*innerPaginator.pageSize)">
    
                  ...
    
              </table>
              <mat-paginator #innerPaginator [length]="element.users.length"
                    [pageSize]="5" [pageSizeOptions]="[5, 10, 20]"
                                                   showFirstLastButtons]="true">
              </mat-paginator>
          </td>
    

    You needn't worry about the "scope" of the templateRef because is inside a *ngFor