Sander Bakker
Sander Bakker

Reputation: 621

Angular dynamically populate table

I'm trying to dynamically populate a table using the following code:

teams.component.ts

import { Component, OnInit } from '@angular/core';
import { first } from 'rxjs/operators';
import { TeamService } from 'src/app/services/team.service';

export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}

@Component({
  selector: 'app-teams',
  templateUrl: './teams.component.html',
  styleUrls: ['./teams.component.scss']
})
export class TeamsComponent implements OnInit {
  public teams : any; 

  tableCols = ['id', 'name'];

  constructor(private teamService : TeamService) { }

  ngOnInit(): void {
    this.teamService.getTeams().pipe(first()).subscribe(
      data => {
        this.teams = data.results
      },
      error => {
        console.log(error.error)
      }
    ) 
  }

}

teams.component.html

<app-table [tableData]="teams" [tableColumns]="tableCols"></app-table>

table.component.ts

import { Component, OnInit, Input, ViewChild } from '@angular/core';
import { MatSort } from '@angular/material/sort';
import { MatPaginator } from '@angular/material/paginator';
import { MatTableDataSource } from '@angular/material/table';

@Component({
  selector: 'app-table',
  templateUrl: './table.component.html',
  styleUrls: ['./table.component.scss']
})
export class TableComponent implements OnInit {
  tableDataSrc: any;
  // tslint:disable-next-line: no-input-rename
  @Input('tableColumns') tableCols: string[];
  @Input() tableData: {}[] = [];

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


  constructor() { }

  ngOnInit() {
    this.tableDataSrc = new MatTableDataSource(this.tableData);
    this.tableDataSrc.sort = this.sort;
    this.tableDataSrc.paginator = this.paginator;
  }

}

table.component.html

<div class="mat-elevation-z8">
<table mat-table [dataSource]="tableDataSrc" matSort class="mat-elevation-z8">
    <ng-container *ngFor="let col of tableCols">
    <ng-container matColumnDef="{{ col }}">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>
        {{ col | titlecase }}
        </th>
        <td mat-cell *matCellDef="let profile">{{ profile }}</td>
    </ng-container>
    </ng-container>

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

<mat-paginator [pageSizeOptions]="[1, 2, 3, 5, 10, 20]" showFirstLastButtons></mat-paginator>
</div>

A 'team' object looks like the following:

{'id': 9, 'name': 'FC Barcelona'} and the teams variable is a list of these objects.

When I navigate to the teams page the table is rendered and stays empty, what am I doing wrong here?

Upvotes: 0

Views: 1000

Answers (1)

ysf
ysf

Reputation: 4844

try replacing this part in table.component.ts

  ngOnInit() {
    this.tableDataSrc = new MatTableDataSource(this.tableData);
    this.tableDataSrc.sort = this.sort;
    this.tableDataSrc.paginator = this.paginator;
  }

with this

  ngOnChanges(changes: SimpleChanges) {
      if(changes.tableData.currentValue) {
          this.tableDataSrc = new MatTableDataSource(this.tableData);
          this.tableDataSrc.sort = this.sort;
          this.tableDataSrc.paginator = this.paginator;
      }
  }

The problem is teams field in TeamsComponent gets initialized after (due to async operation) TableComponents OnInit phase. If you change ngOnInit with ngOnChanges whenever teams field changes TableComponent becomes aware of it.

Further reading: https://angular.io/guide/lifecycle-hooks#using-change-detection-hooks

Upvotes: 1

Related Questions