1

I'm struggling with the Angular mat-table library. I got an app with a Node.js backend and an Angular frontend. The node app provides data from a MySQL database in JSON.

Now I want to display this data in a mat-table. I have logged the data in the console, which allows me to see that the data is actually retrieved but just not displayed.

Data in Console

However, the HTML table is empty:

empty html

This is my Angular component:

component.html

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8 demo-table">
  <ng-container matColumnDef="id">
    <th mat-header-cell *matHeaderCellDef>ID</th>
    <td mat-cell *matCellDef="let element">{{element.id}}</td>
  </ng-container>
  <ng-container matColumnDef="name">
    <th mat-header-cell *matHeaderCellDef>Name</th>
    <td mat-cell *matCellDef="let element">{{element.name}}</td>
  </ng-container>
  <ng-container matColumnDef="pop">
    <th mat-header-cell *matHeaderCellDef>Population</th>
    <td mat-cell *matCellDef="let element">{{element.population}}</td>
  </ng-container>


  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr
      mat-row
      (click)="clickedRows.add(row)"
      [class.demo-row-is-clicked]="clickedRows.has(row)"
      *matRowDef="let row; columns: displayedColumns;"
  ></tr>
</table>

component.ts

import {Component, OnInit,ViewChild} from '@angular/core';
import { Player } from '../player';
import { PlayerService } from '../player.service';
import { MatTableDataSource } from '@angular/material/table';
import {MatPaginator} from '@angular/material/paginator';
import {MatSort, SortDirection} from '@angular/material/sort';

/**
 * @title Binding event handlers and properties to the table rows.
 */
@Component({
  selector: 'app-players',
  styleUrls: ['players.component.css'],
  templateUrl: 'players.component.html',
})
export class PlayersComponent implements OnInit {
  displayedColumns: string[] = ['id', 'name', 'pop'];
  dataSource = new MatTableDataSource<Player>();

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

  constructor(private playerService:PlayerService) { }

  ngOnInit(): void {
    this.getPlayers();
  }

  getPlayers() {
    this.playerService.getPlayers().subscribe(players => {
      console.log(players);
      this.dataSource.data = players;
      this.dataSource.paginator = this.paginator;
      this.dataSource.sort = this.sort;
    });
  }
  clickedRows = new Set<Player>();
}

player.service.ts

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

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

  constructor(private http: HttpClient) { }
  rootURL = '/api';
  getPlayers(): Observable<Player[]> {
    return this.http.get<Player[]>(this.rootURL+ '/players');
  }
}

Any ideas on this?

EDIT: Could it have something to do with how the array comes back from the API? In Node.js it is retrieved with sequelize and maybe it is the response?

// Get all Players
exports.findAll = (req, res) => {
    Player.findAll().then((players) => {
    // Send all players as response
    res.status(200).json({
      status: true,
      data: players,
    });
  });
};
4
  • displayedColumns: string[] = ['id', 'name', 'pop'];? shouldn't that be population? Commented Sep 8, 2021 at 18:58
  • i think its just a string to identify the correct column in the mat-table html definition which is defined as <ng-container matColumnDef="pop"> EDIT: Yes, i updated the code - nothing changed in behaviour. Commented Sep 8, 2021 at 19:00
  • datasource binding should be [dataSource]="dataSource.data" and this.dataSource.data = players.data;(according to the screenshot of response). I didn't understand your paginator and sort. I have used it like this. material.angular.io/components/table/examples#table-http Commented Sep 8, 2021 at 19:13
  • the paginator and sort in my example are properties from MatTableDataSource class. see material.angular.io/components/table/api#MatTableDataSource Commented Sep 8, 2021 at 22:22

2 Answers 2

2

Issue

The data returned based on the screenshot and Node.js API is not Player array, but it is an object with status and data properties.

{
  "status": 200,
  "data": [...]
}

This line expected that HTTP GET to receive Player array which is conflict with your data.

this.http.get<Player[]>(this.rootURL+ '/players');

Hence, it returns Observable with an empty array and your <mat-table> will not show the data.


Solution

Transform the data to Player array with map rxjs operator.

import { map } from 'rxjs';

getPlayers(): Observable<Player[]> {
  return this.http
    .get(this.rootURL+ '/players')
    .pipe(map((response: any) => response.data as Player[]));
}

Sample Solution on StackBlitz

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

1 Comment

this works, thanks a lot! I already thought of something like this, which is why I have attached the API code in my EDIT part.
0

Create a instance of MatTableDataSource and assign to data Source. Try this option

this.dataSource = new MatTableDataSource(players);
this.dataSource.sort = this.sort;

Ref: Using HTTP GET request to fetch data in an Angular Material Table

1 Comment

Same issue.. i replaced my code with the new dataSource instance(this.dataSource = new MatTableDataSource(players);) but its still the same behaviour. array is retrieved but not displayed.

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.