Search code examples
angulartypescriptpaginationangular-materialangular11

Angular Material - Paginate dynamic table


I have a dynamic table in Angular Material, where I collect the data using an API from an external database. I'm trying to paginate the table but I only find examples of tables with predefined data and I can't adopt it.

I have added my HTML and my current .ts in which the only thing I do is show the data in a table, in the HTML I have added the mat-paginator tag to show it but I don't know how to make it work in the .ts.

This is my component.ts:

import { Component, OnInit, ViewChild } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { ClientService } from '../../services/clients.service';
import { Client } from '../../domain/clients';
import { MatPaginator } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';

export class ClientsComponent implements OnInit {

  @ViewChild(MatPaginator) paginator: MatPaginator;

  public displayedColumns: string[] = ['name'];
  public client: Client;
  public clients: Client[];

  constructor(
    public fb: FormBuilder,
    private clienteService: ClienteService
  ) { }

  ngOnInit() {
    this.getClients();
  }

  getClientes() {
    this.clienteService.list()
    .subscribe(client => this.clientes = client);
  }

}

This is my component.html:

<div class="title">Customers</div>
<mat-divider></mat-divider>

<div fxLayout="column" fxLayoutGap="10px" class="m-3">
  <mat-card class="mat-elevation-z8">
    <mat-table [dataSource]="clients">

      <ng-container matColumnDef="name">
        <mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
        <mat-cell *matCellDef="let clients; let i = index">
          <mat-form-field floatLabel="never" [appearance]="editIndex != i ? 'none' : 'legacy'">
            <input matInput placeholder="{{clients.name}}" [(ngModel)]="clients.name" [readonly]="editIndex!=i">
          </mat-form-field>
        </mat-cell>
      </ng-container>
      </ng-container>

      <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
      <mat-row *matRowDef="let col; columns: displayedColumns;"></mat-row>

    </mat-table>
    <mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>
  </mat-card>
</div>

Solution

  • You should apply MatTableDataSource as the datasource, it contains the paginator property for table pagination.

    SOLUTION

    .component.html

    <mat-table [dataSource]="this.dataSource">
    
        <ng-container matColumnDef="name">
            <mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
            <mat-cell *matCellDef="let client; let i = index">
              <mat-form-field floatLabel="never" [appearance]="editIndex != i ? 'none' : 'legacy'">
                <input matInput placeholder="{{client.name}}" [(ngModel)]="client.name" [readonly]="editIndex!=i">
              </mat-form-field>
            </mat-cell>
        </ng-container>
    
        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
        <mat-row *matRowDef="let col; columns: displayedColumns;"></mat-row>
        
    </mat-table>
    
    <mat-paginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons></mat-paginator>
    

    .component.ts

    export class ClientsComponent implements OnInit {
      ...
    
      dataSource: MatTableDataSource<Client>;
      @ViewChild(MatPaginator) paginator: MatPaginator;
    
      ...
    
      getClients() {
        this.clienteService.list().subscribe(client => {
          this.clients = client;
          this.dataSource = new MatTableDataSource(this.clients);
          this.dataSource.paginator = this.paginator;
        });
      }
    }
    

    Solution on StackBlitz


    RECOMMENDATION(S)

    <mat-form-field floatLabel="never" [appearance]="editIndex != i ? 'none' : 'legacy'">
        <input matInput placeholder="{{client.name}}" [(ngModel)]="client.name" [readonly]="editIndex!=i">
    </mat-form-field>
    

    For [appearance], you should review it and make sure to pass the supported value for MatFormFieldAppearance as listed in Angular documentation.

    type MatFormFieldAppearance = 'legacy' | 'standard' | 'fill' | 'outline';
    

    You will get the error as below if you didn't turn off strict mode for Angular compiler in tsconfig.json.

    Type '"none"' is not assignable to type 'MatFormFieldAppearance'.

    For this scenario, I commented JSON for angularCompilerOptions to solve mentioned concern.

    tsconfig.json

    {
      ...
    },
    // "angularCompilerOptions": {
    //   "enableIvy": true,
    //   "fullTemplateTypeCheck": true,
    //   "strictInjectionParameters": true
    // }