1

In my attempts to use angular material tables to display data, I have found that when using hardcoded inline json, my table sorts as expected. However, when retrieving json via http.get(), the sort no longer works.

A sample service created to illustrate this question:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root',
})
export class ApiService {
  constructor(private http: HttpClient) {}

  getDataHttp(): Observable<any> {
    return this.http.get('assets/data.json');
  }

  getDataInline(): Observable<any> {
    var data = [
      . . .
    ];
    return of(data);
  }
}

and the respective table component:

import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import { ApiService } from '../../services/api.service';

@Component({
  selector: 'app-table',
  templateUrl: './table.component.html',
  styleUrls: ['./table.component.css'],
})
export class TableComponent implements OnInit {
  @Input() name: string = '';
  displayedColumns = ['id', 'name', 'value'];
  dataSource: MatTableDataSource<any>;

  @ViewChild(MatSort) sort!: MatSort;

  constructor(private api: ApiService) {
    this.dataSource = new MatTableDataSource();
  }

  ngOnInit(): void {
    if (this.name === 'Inline') {
      this.api.getDataInline().subscribe((response) => {
        this.dataSource = new MatTableDataSource(response);
      });
    } else if (this.name === 'Http') {
      this.api.getDataHttp().subscribe((response) => {
        this.dataSource = new MatTableDataSource(response);
      });
    }
  }

  ngAfterViewInit() {
    this.dataSource.sort = this.sort;
  }
}

and the corresponding view:

<div>
  <h5>{{ name }}</h5>
  <table mat-table [dataSource]="dataSource" matSort>
    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>

    <ng-container matColumnDef="id">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>Id</th>
      <td mat-cell *matCellDef="let row">{{ row.id }}</td>
    </ng-container>

    <ng-container matColumnDef="name">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>Name</th>
      <td mat-cell *matCellDef="let row">{{ row.name }}</td>
    </ng-container>

    <ng-container matColumnDef="value">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>Value</th>
      <td mat-cell *matCellDef="let row">{{ row.value }}</td>
    </ng-container>
  </table>
</div>

Stackblitz: https://stackblitz.com/edit/angular-ivy-qk3s2y

Why does sorting work for the inline table, but not for the http table?

1
  • Because http request is async. this.dataSource.sort = this.sort; is called before the datasource is initialized. If you move that code into the http subscribe it will work as expected Commented Dec 3, 2021 at 19:10

2 Answers 2

4

This:

ngAfterViewInit() {
  this.dataSource.sort = this.sort;
}

is executed before the http-request is done. We need to remember this is asynchronous, so you should set the sort after the data has been received:

  this.api.getDataHttp().subscribe((response) => {
    this.dataSource = new MatTableDataSource(response);
    this.dataSource.sort = this.sort; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  });

STACKBLITZ

Sign up to request clarification or add additional context in comments.

Comments

0

this way sort may work or not depending how long data reaquest will take.
There is a reason why AfterViewInit is used to set sort, this.sort is undefined before this hook just console.log it in onInit and AfterViewInit to check.

look at https://angular.io/api/core/ViewChild example2

you can simply declare empty table in youre component

 dataSource: MatTableDataSource<any> = new MatTableDataSource([]) ;

and after you receive data

 this.dataSource.data = response;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.