Search code examples
angulartypescriptangular-materialpaginator

How to use Material Paginator in a datatable in Angular?


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 = [];
      }