How to use Material Paginator in a datatable in Angular?

Issue

I’m trying to make the Angular Material pager functional to a table where the data comes from a service. I have followed a couple of tutorials from the Angular Material documentation, but the pager is not working

Code from html component:

  <div>
    <table mat-table [dataSource]="dataSource" class="mat-elevation-z8 table-left">

              <ng-container [matColumnDef]="column" *ngFor="let column of displayedColumns">
              <th id="head" mat-header-cell *matHeaderCellDef> {{column}} </th>

              <ng-container *ngIf="column != 'cities'; else optionsTemplate">
                   <td mat-cell *matCellDef="let element"> {{element[column]}} </td>
              </ng-container>
        
              <ng-template #optionsTemplate>
                <td mat-cell *matCellDef="let element" class="action-link">
                     <button mat-raised-button (click)="loadCity(element.idDepartment)">Cities</button>
                </td>
              </ng-template>
          </ng-container>

          <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
          <tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
    </table>

    <table mat-table [dataSource]="dataSourceCity" class="mat-elevation-z8">
        <ng-container [matColumnDef]="column" *ngFor="let column of displayedColumnsC">
          <th id="head" mat-header-cell *matHeaderCellDef> {{column}} </th>
          <td mat-cell *matCellDef="let element"> {{element[column]}} </td>
        </ng-container>

        <tr mat-header-row *matHeaderRowDef="columnsToDisplayC"></tr>
        <tr mat-row *matRowDef="let row; columns: columnsToDisplayC;"></tr>
    </table>
    <mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>
 </div>

Code from ts component:

import { Component, OnInit, ViewChild} from '@angular/core';
import { MatPaginator } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';
import { DepartmentService } from '../../_service/department.service';
import { Department } from 'src/app/_model/department';

@Component({
   selector: 'app-search',
   templateUrl: './search.component.html',
   styleUrls: ['./search.component.css'],
})
export class SearchComponent implements OnInit {
      displayedColumns: string[] = ['idDepartment', 'name', 'cities'];
      columnsToDisplay: string[] = this.displayedColumns.slice();
      depList: Department[] = [];
      dataSource = [];
      
      displayedColumnsC: string[] = ['idCity', 'name'];
      columnsToDisplayC: string[] = this.displayedColumnsC.slice();
      cityList: any[] = [];
      dataSourceCity = new MatTableDataSource(this.cityList);

      @ViewChild(MatPaginator) paginator: MatPaginator;

      constructor(private departService: DepartmentService) { }
      
      ngOnInit(): void {
            this.dataSourceCity.paginator = this.paginator;

            this.depList = [];
            this.departService.list().subscribe(data => {
                 data.forEach(element => {
                 this.depList.push({idDepartment: element.idDepartment, name: element.name});
                });
                this.dataSource = this.depList;
            });
      }

      loadCity(idDepartment): void {
            this.departService.listCities(idDepartament).subscribe(data => {
            data.forEach(element => {
                 this.cityList.push({idCity: element.idCity, name: element.name});
            });
            this.dataSourceCity.data = this.cityList;
            console.log(this.dataSourceCity);
      });
      this.dataSourceCity.data = [];
      this.cityList = [];
   }
}

The data is displayed correctly in the table, but the paginator does not work, it is as if the data source was not "detected" by the paginator.

Solution

You have to assign the paginator after the datasource is defined:

  loadCity(idDepartment): void {
    this.departService.listCities(idDepartament).subscribe((data) => {
      data.forEach((element) => {
        this.cityList.push({ idCity: element.idCity, name: element.name });
      });
      this.dataSourceCity.data = this.cityList;
      this.dataSourceCity.paginator = this.paginator
      console.log(this.dataSourceCity);
    });
    this.dataSourceCity.data = [];
    this.cityList = [];
  }

Answered By – Meqwz

Answer Checked By – Robin (AngularFixing Admin)

Leave a Reply

Your email address will not be published.