Search code examples
jsonsortingrxjsangular-materialmat-tab

How to implement (sort, pagination) for Angular Material table which retrieves data through Rest API (JSON)?


I have this Material table that displays data from a JSON url through Rest API. I now want to use sort\pagination on the material table but can't get through it. Below are the screenshots. How do I refer MatTableDataSource and UserDataSource both together ? I want to stick to using Observable. Please advise, I am new to Angular.

Component.ts

    @Component({
  selector: 'app-tablefilter', 
  templateUrl: './tablefilter.component.html',
  styleUrls: ['./tablefilter.component.scss']
})
export class TablefilterComponent implements OnInit {

  @ViewChild(MatSort, {static: true}) sort: MatSort; 

  displayedColumns: string[] = ['name','email','phone','website', 'address']; 
  dataSource = new UserDataSource(this.dataService );

  constructor(private dataService: DataService) {}



  ngOnInit() {
  }

}

export class UserDataSource extends DataSource<any> {
  constructor(private dataService: DataService) {
    super();
  }
  connect(): Observable<Contacts[]> {
    return this.dataService.fetchPosts();
  }
  disconnect() {}
}

HTML

    <table mat-table matSort  class="mat-elevation-z8" [dataSource]="dataSource">
    <ng-container matColumnDef="phone">
        <th mat-header-cell *matHeaderCellDef mat-sort-header> phone
             </th>
        <td mat-cell *matCellDef="let contacts">{{contacts.phone}}  </td>
      </ng-container>
    <ng-container matColumnDef="name">
      <th mat-header-cell *matHeaderCellDef mat-sort-header> name </th>
      <td mat-cell *matCellDef="let contacts"> {{contacts.name}} </td>
    </ng-container>

    <ng-container matColumnDef="email">
        <th mat-header-cell *matHeaderCellDef> email </th>
        <td mat-cell *matCellDef="let contacts"> {{contacts.email}} </td>
      </ng-container>

      <ng-container matColumnDef="website">
        <th mat-header-cell *matHeaderCellDef> website </th>
        <td mat-cell *matCellDef="let contacts"> {{contacts.website}} </td>
      </ng-container>


      <ng-container matColumnDef="address">
        <th mat-header-cell *matHeaderCellDef> address </th>
        <td mat-cell *matCellDef="let contacts"> {{contacts.address.street}} </td>
      </ng-container>

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

Service -data.service.ts

    import { Injectable } from '@angular/core';
import{ Observable } from 'rxjs/observable';
import { HttpClient } from '@angular/common/http';
import {Contacts} from '../models/contacts.model';
import { map, tap } from 'rxjs/operators';

import 'rxjs/add/operator/map';

@Injectable({
  providedIn: 'root'
})
export class DataService {

   private serviceUrl = 'https://jsonplaceholder.typicode.com/users';

  constructor( private http: HttpClient ) { }


  fetchPosts(): Observable<Contacts[]> {
    return this.http.get<Contacts[]>(this.serviceUrl )


  }
}

Solution

  • MatTableDataSource is a data source that accepts a client-side data array and includes native support of filtering, sorting (using MatSort), and pagination (using MatPaginator). Class MatTableDataSource extends the abstract class DataSource, hence there's no need to provide custom implementation as you intend to do with UserDataSource.

    Therefore, get rid of UserDataSource and rewrite your TablefilterComponent as follows.

    export class TablefilterComponent implements OnInit {
      displayedColumns: string[] = ['phone', 'name', 'email', 'website', 'address']; 
      dataSource: MatTableDataSource<Contact>; 
    
      @ViewChild(MatSort, {static: true}) sort: MatSort;
      @ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
    
      constructor(private dataService: DataService) {}
    
      ngOnInit() {
        this.dataService.fetchPosts().subscribe(contacts => {
           this.dataSource = new MatTableDataSource(contacts);
           this.dataSource.sort = this.sort;
           this.dataSource.paginator = this.paginator;
        });
      }
    }
    

    Please have a look at the following StackBlitz