Hitesh Kansagara
Hitesh Kansagara

Reputation: 3526

Angular mat-table display dynamic data from key value json in each row

I have below json and want to render in material table in angular

var res = '[
  {
    "DynamicName": "xyz",
    "DynamicLevel": "xyz",
    "DynamicLevel": "xyz",
    "DynamicLevel": "xyz",
    "dynamic": "xyz"
  },
  {
    "DynamicName": "xyz",
    "DynamicLevel": "xyz",
    "DynamicLevel": "xyz",
    "DynamicLevel": "xyz",
    "dynamic": "xyz"
  },
  {
    "DynamicName": "xyz",
    "DynamicLevel": "xyz",
    "DynamicLevel": "xyz",
    "DynamicLevel": "xyz",
    "dynamic": "xyz"
  }]';

In second response this json will be like below

var res = '[
      {
        "DynamicCity": "xyz",
        "DynamicCountry": "xyz",
        "DynamicState": "xyz",
        "DynamicRegion": "xyz",
        "dynamic": "xyz"
      },
      {
        "DynamicCity": "xyz",
        "DynamicCountry": "xyz",
        "DynamicState": "xyz",
        "DynamicRegion": "xyz",
        "dynamic": "xyz"
      },
      {
        "DynamicCity": "xyz",
        "DynamicCountry": "xyz",
        "DynamicState": "xyz",
        "DynamicRegion": "xyz",
        "dynamic": "xyz"
      }]';

this data need to render in material table I have tried like this

// properties of the class
displayedColumns: string[];//columns should be create dynamically
dataSource = res;

    <table mat-table [dataSource]="dataSource | keyvalue" class="mat-elevation-z8">
      <ng-container matColumnDef="key">
        <th mat-header-cell *matHeaderCellDef> {{element.key}}</th>
        <td mat-cell *matCellDef="let element"> {{element.value}} </td>
      </ng-container>  
    
      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
    </table>

I need output like below

enter image description here

Here, dynamic column means in each api call we get different data for this column names so it will be changed every api call so I am not able to bind it to material table. Please help me to solve this issue of binding json data to material table. reference URLs:-

  1. Angular mat-table display dynamic key value pair in each row
  2. https://www.interfacecreator.com/2018/10/angular-material-table-dynamic.html

Upvotes: 2

Views: 4851

Answers (4)

Aviv Vanunu
Aviv Vanunu

Reputation: 11

https://material.angular.io/components/table/examples :

<table mat-table [dataSource]="data" class="mat-elevation-z8">
 <ng-container [matColumnDef]="column" *ngFor="let column of 
 displayedColumns">
  <th mat-header-cell *matHeaderCellDef> {{column}} </th>
  <td mat-cell *matCellDef="let element"> {{element[column]}} </td>
 </ng-container>
 <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
 <tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
</table>

Upvotes: 1

Kaushal Makwana
Kaushal Makwana

Reputation: 26

 import { Component,OnInit } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.sass']
})
export class AppComponent implements OnInit {
  title = 'jsonDemo';

  ELEMENT_DATA1 = [
    { 'DynamiCCity': 'Hydrogen' , 'DynamicCountry' : 'Country', 'DynamicState' : 'State' , 'DynamicRegion' :'DynamicRegion' , 'dynamic' :'dynamic' },
    { 'DynamiCCity': 'Hydrogen 1' , 'DynamicCountry' : 'Country 1', 'DynamicState' : 'State 1' , 'DynamicRegion' :'DynamicRegion 1' , 'dynamic':'dynamic 1' },
  ];

  displayedColumns: string[] = [];
  dataSource1 = this.ELEMENT_DATA1;
 
  ngOnInit(): void
  {
    this.displayedColumns = Object.getOwnPropertyNames(this.ELEMENT_DATA1[0]);
  }
}


<h2>Demo</h2>

<style>
  table {
  width: 100%;
}
</style>


<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
  <ng-container *ngFor="let item of displayedColumns" matColumnDef="{{item}}">
    <th mat-header-cell *matHeaderCellDef> {{item}} </th>
    <td mat-cell *matCellDef="let element"> {{ element[item] }}</td>
  </ng-container>

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


<router-outlet></router-outlet>

I Hope Above Code is Working Demo of your Issue. It will work as expected.

Upvotes: 1

Lars R&#248;dal
Lars R&#248;dal

Reputation: 876

I created a Stackblitz for you. This should work with any lists with objects with simple values (will take the keys from the first object, so all the objects needs to be the same for the current list (no way around this without creating separate tables)): https://stackblitz.com/edit/angular-pqgny8?file=src/app/table-basic-example.html

HTML:

<table *ngIf="dataSource && displayedColumns" mat-table [dataSource]="dataSource" class="mat-elevation-z8">

  <ng-container *ngFor="let k of displayedColumns">
    <ng-container [matColumnDef]="k">
      <th mat-header-cell *matHeaderCellDef> {{k}}</th>
      <td mat-cell *matCellDef="let element"> {{element[k]}} </td>
    </ng-container>
  </ng-container>

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

TS:

getData() {
this.dataSource = ELEMENT_DATA; // ELEMENT_DATA is the data from your backend
this.displayedColumns = Object.keys(this.dataSource[0]).map(k => k)

}

Upvotes: 2

Hamada
Hamada

Reputation: 1898

Html

<div class="demo-button-container">
  <button mat-raised-button (click)="addData()" class="demo-button">
    Add data
  </button>
  <button
      mat-raised-button
      [disabled]="!dataSource.length"
      (click)="removeData()"
      class="demo-button">
    Remove data
  </button>
</div>

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8 demo-table">
  <!-- Position Column -->
 <ng-container [matColumnDef]="col" *ngFor="let col of displayedColumns">
      <th mat-header-cell *matHeaderCellDef>
        {{col}}
      </th>
      <td mat-cell *matCellDef="let element">
        {{element[col]}}
      </td>
    </ng-container>

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

ts

import {Component, ViewChild} from '@angular/core';
import {MatTable} from '@angular/material/table';

export interface dynElement {
  DynamicName: string,
  DynamicLevel_1: string,
  DynamicLevel_2:string,
  DynamicLevel_3:string,
  dynamic:string
}

const ELEMENT_DATA: any [] = [
  {
    DynamicName: "xyz",
    DynamicLevel_1: "xyz",
    DynamicLevel_2: "xyz",
    DynamicLevel_3: "xyz",
    dynamic: "xyz"
  },
  {
    DynamicName: "xyz",
    DynamicLevel_1: "xyz",
    DynamicLevel_2: "xyz",
    DynamicLevel_3: "xyz",
    dynamic: "xyz"
  },
  {
    DynamicName: "xyz",
    DynamicLevel_1: "xyz",
    DynamicLevel_2: "xyz",
    DynamicLevel_3: "xyz",
    dynamic: "xyz"
  },
  {
    DynamicName: "xyz",
    DynamicLevel_1: "xyz",
    DynamicLevel_2: "xyz",
    DynamicLevel_3: "xyz",
    dynamic: "xyz"
  },
]
@Component({
  selector: 'table-dynamic-array-data-example',
  styleUrls: ['table-dynamic-array-data-example.css'],
  templateUrl: 'table-dynamic-array-data-example.html',
})
export class TableDynamicArrayDataExample {
  
  // your Object Key Object.keys(obj)

  displayedColumns: string[] = [...Object.keys(ELEMENT_DATA[0])];
  dataSource = [...ELEMENT_DATA]; // you can pass your data from backend here

  @ViewChild(MatTable) table: MatTable<any>;

  addData() {
    const randomElementIndex = Math.floor(Math.random() * ELEMENT_DATA.length);
    this.dataSource.push(ELEMENT_DATA[randomElementIndex]);
    this.table.renderRows();
  }

  removeData() {
    this.dataSource.pop();
    this.table.renderRows();
  }
}

demo in stackblitz

Upvotes: 1

Related Questions