DEV Community

Cover image for Adding multiple MatPaginators to the same DataSource
Robin
Robin

Posted on

Adding multiple MatPaginators to the same DataSource

This short guide is for all Angular developers using the Angular Material Library. A customer requested the following feature:

Please show the (Mat)Paginator above and below all tables (which are MatTables).

The problem here: You can only connect a single MatPaginator to a DataSource that holds the data for the table.

First I tried to use templates to display the paginator twice on the same page, but without success. The second datepicker didn't work at all.

Second, I thought about implementing the pagination logic by myself, as you do it with server-side pagination. As I had to edit several pages, this did not seem to be the best way to do it.

One step before the final implementation, I also experimented with using different signals to synchronise the properties to the second paginator instance. The final solution is a bit simpler.

Implementation

Template:

<!-- first paginator (standard implementation with some additional options) --> 
<mat-paginator
  pageSize="50"
  [pageSizeOptions]="[10, 25, 50, 100]"
  [showFirstLastButtons]="false">
</mat-paginator>

<!-- MatTable as usual --> 
<table mat-table [dataSource]="dataSource">...</table

<!-- second paginator (synced explicit to the dataSource) -->
@if (dataSource.paginator; as paginator) {
  <mat-paginator
    (page)="pageChanged($event)"
    [pageSize]="paginator.pageSize"
    [length]="paginator.length"
    [pageIndex]="paginator.pageIndex"
    [pageSizeOptions]="paginator.pageSizeOptions"
    [showFirstLastButtons]="paginator.showFirstLastButtons">
  </mat-paginator>
}
Enter fullscreen mode Exit fullscreen mode

Component:

@Component(/* ... */)
export class DocumentListComponent implements AfterViewInit {
  // input of the data
  documents = input.required<Document[]>();

  // dataSource of the table
  dataSource = new MatTableDataSource<Document>();

  // finds the first MatPaginator instance in the view
  @ViewChild(MatPaginator, { static: true })
  paginator!: MatPaginator;

  // listening to changes in the documents input
  constructor() {
    effect(() => (this.dataSource.data = this.documents()));
  }

  // connecting the first paginator to the dataSource
  ngAfterViewInit(): void {
    this.dataSource.paginator = this.paginator;
  }

  // handling page changes from the bottom paginator
  pageChanged(event: PageEvent) {
    const dataSourcePaginator = this.dataSource.paginator;

    if (dataSourcePaginator) {
      dataSourcePaginator.pageIndex = event.pageIndex;
      dataSourcePaginator._changePageSize(event.pageSize);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Explanation

How does it work? Implement the MatTable and the first MatPaginator as usual, connect them in the ngAfterViewInit() hook.

The second paginator will not be updated automatically, so we need to pass in all the required properties that we can retrieve from the first paginator, which also controls the displayed data in the table.

Finally we also need to handle the navigation events of the bottom paginator. Therefore we added a pageChanged() method, that updates the state of the first paginator and the dataSource along with it.

Top comments (0)