DEV Community

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

Posted on • Edited 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 paginator 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.

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay