Angular material pagination and sort not working as expected

Viewed 659

I have implemented angular material datatable which contains pagination and sorting but after fetching records from the database it's not working as expected.

report.componenet.html:

<table mat-table matSort [dataSource]="dataSource">

          <!-- Position Column -->
          <ng-container matColumnDef="date">
            <th mat-header-cell *matHeaderCellDef mat-sort-header class="hide-arrow"> Date </th>
            <td mat-cell *matCellDef="let element"> {{element.date}} </td>
          </ng-container>
      
          <!-- Name Column -->
          <ng-container matColumnDef="name">
            <th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
            <td mat-cell *matCellDef="let element"> {{element.name}} </td>
          </ng-container>
      
          <!-- Weight Column -->
          <ng-container matColumnDef="download">
            <th mat-header-cell *matHeaderCellDef mat-sort-header> Download </th>
            <td mat-cell *matCellDef="let element"> 
              <a [href]="element['download']['log']" target="_blank" *ngIf="element['download']['log'] !== ''" download>Log</a> <div *ngIf="element['download']['dataReport'] !== ''">|</div>
              <a [href]="element['download']['dataReport']" target="_blank" *ngIf="element['download']['dataReport'] !== ''">Data report</a> <div *ngIf="element['download']['htmlReport'] !== ''">|</div>
              <a [href]="element['download']['htmlReport']" target="_blank" *ngIf="element['download']['htmlReport'] !== ''">HTML report</a>
            </td>
          </ng-container>
      
          <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
          <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
        </table>
      
        <mat-paginator [pageSizeOptions]="[5, 10, 20]"
                       showFirstLastButtons 
                       aria-label="Select page of periodic elements">
        </mat-paginator>

report.component.ts:

displayedColumns: string[] = ['date', 'name', 'download'];
  dataSource = new MatTableDataSource<PeriodicElement>([]);

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;
ngAfterViewInit() {
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
  }
getTestReportData() {
    this.loginService.startSpinner(true);
    this.service.fetchTestReportData().subscribe((resp: any) => {
      console.log('resp python', resp);
      this.loginService.startSpinner(false);
      if(resp.status && resp.status === 'success') {
        if(resp.body && resp.body.status && resp.body.status === 'success') {
          if(resp.body.data && resp.body.data.length > 0) {
            this.dataSource.data = resp.body.data;
            this.length = resp.body.data.length;
            console.log('datasource', this.dataSource);
          }
        }else{
          this.presentAlert(resp.msg, 'danger', ALERT_TIMEOUT);
        }
      }else{
        this.presentAlert(resp.msg, 'danger', ALERT_TIMEOUT);
      }
    })
  }

I am fetching records from the server and appending them into the table but in this case, the pagination and sorting both are not getting reflected. check the sample output below.

enter image description here

There are two records present but it's showing 0 of 0 and also sorting is not working as expected. I need the pagination number and sorting should work as expected. How can I resolve this?

1 Answers

I have the same issue. In my case i solve this way.

component.html

<app-loading *ngIf="isLoading$ | async"></app-loading>
<div *ngIf="(isLoading$ | async) === false">
   <ng-container *ngIf="dataSource.data.length >= 1; else noData">
      <mat-paginator [pageSizeOptions]="[10, 25, 50]"></mat-paginator>
      <mat-table [dataSource]="dataSource" matSort>
        ...
      </mat-table>
   </ng-container>
   <ng-template #noData>
      <h3>Ops...</h3>
      <p>There is no data...</p>
   </ng-template>
</div>

and the component.ts

import { Component, OnInit, ViewChild } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';
import { MatSort } from '@angular/material/sort';
import { MatPaginator } from '@angular/material/paginator';
...
export class Component implements OnInit {
  dataSource = new MatTableDataSource<any>();
  isLoading$: Observable<boolean>;
  paginator: MatPaginator;
  sort: MatSort;
  @ViewChild(MatPaginator) set matPaginator(mp: MatPaginator) {
    this.paginator = mp;
    this.dataSource.paginator = this.paginator;
  }
  @ViewChild(MatSort) set matSort(ms: MatSort) {
    this.sort = ms;
    this.dataSource.sort = this.sort;
  }

Use the ViewChild to bind the paginator and the sort to sync with server response async. Then pass set to be able to set async the values in paginator, sort or filter...

ngAfterViewInit() cycle will run right after the component init. And maybe be serve wont have response the data yet. As i said, in my case i could be fetch async the paginator async with the server response using set, take a look in https://angular.io/api/core/ViewChild

Keep coding \m/

Related