Philippe Merle
Philippe Merle

Reputation: 125

dynamic property binding in a table in angular 6

Good Afternoon,

I am beginning Angular. I want to make a table that I expect to use in many locations in my applications.

This table will be a child component of many parent components and thus I want these components to pass the table an array of headers and an array of lines.

Here is an example of the parent ts:

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { PrestationService } from '../services/prestation.service';

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

  constructor(private fb:FormBuilder, private prestationService:PrestationService) { }

  TITLE:String = "Créer une prestation"
  headers = ['libelle', 'Montant', 'Valable jusqu\'au']
  prestations;
  form:FormGroup;
  msg;

  ngOnInit() {
    this.loadPrestations();
    this.form = this.fb.group({
      libelle:'',
      montant:'',
      date_validite: new Date()
    })
  }

  addPrestation(data){
    this.prestationService.add(data).subscribe(
      data => this.msg = data,
      err => this.msg = err
    )
    this.loadPrestations();
  }

  loadPrestations(){
    this.prestationService.getPrestations().subscribe(
      data => this.prestations = data,
      err => this.msg  = err
    )
  }

}

parent .html (minus unnecessary information)

<div class="container tbl-borders spacer">
    <app-view-title [title]="this.TITLE"></app-view-title>
    <app-view-table [headers]="this.headers" [rows]="this.prestations"></app-view-table>

In the html stuff, I pass the array of headers hardCoded in my .ts and an array of object populated directly from my database.

In the child component i retrieve the 2 tables and there i am stuck. I looked around the internet to find solutions but noned fitted what I expect to do in the end.

here is the child component.ts :

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

@Component({
  selector: 'app-view-table',
  templateUrl: './view-table.component.html',
  styleUrls: ['./view-table.component.css']
})
export class ViewTableComponent {

  private _headers:String[];
  private _rows:Array<Object>;

  @Input()
  set headers(headers:String[]){
    this._headers = headers
  }

  @Input()
  set rows(rows:Array<Object>){
    this._rows = rows;
  }

  get headers(){return this._headers}
  get rows(){return this._rows};

}

and the html :

<table class="table table-stripped table-hover table-sm">
  <thead >
    <th *ngFor="let header of headers">{{header}}</th>
    <th>Action</th>
  </thead>
  <tbody>
    <tr *ngFor="let row of rows, i as index">
      <td>{{row.libelle}}</td>
      <td>{{row.montant}}</td>
      <td>{{row.date_validite}}</td>
      <td>
        <div class="row">
        <button class="btn btn-outline-success btn-sm ">edit</button>
        <button class="btn btn-outline-success btn-sm ">Delete</button>
        </div>
      </td>
    </tr>
  </tbody>
</table>

The table headers are working as expected but the rows are not, I tried with keyvalue pipe but the data comes unordered and won't fit the right column header. Above html is incorrect because if i have to explicitely name each property (such as libelle, montant, etc...) this table component couldn't be used everywhere , it will depend on the array property names i will pass into that component argument.

Hope you understand my problem and that you can put me on the right way.

EDIT Here is the dynamic table after correction :

<table class="table table-stripped table-hover table-sm">
  <thead >
    <th *ngFor="let header of headers">{{header.titreColonne}}</th>
    <th>Action</th>
  </thead>
  <tbody>
    <tr *ngFor="let row of rows">
      <td *ngFor="let header of headers">
        {{row[header.key]}}
      </td>
      <div class="col-sm-4 row">
          <button class="btn btn-outline-success btn-sm " *ngFor="let button of buttons" (click)="buttonEvent(button, row.id)">{{button}}</button>
       </div>
    </tr>
  </tbody>
</table>

I modified my header array as such

 headers = [
    {titreColonne:"Libellé", key:"libelle"},
    {titreColonne:"Montant € HT", key:"montant"},
    {titreColonne:"Date Fin validité", key:"dateFinValidite"}
  ]

Upvotes: 1

Views: 12084

Answers (1)

Dmitriy Kavraiskyi
Dmitriy Kavraiskyi

Reputation: 319

The only way to make correctly dynamic table is to have columns names equal to keys of object. Then you could loop object properties by column names inside an array of data. Here is small example.

    <table>
      <thead>
        <tr>
          <th *ngFor="let col of data.ColumnNames">{{ col }}</th>
        </tr>
      </thead>
      <tbody>
      <tr *ngFor="let row of data.Rows">
        <td *ngFor="let col of data.ColumnNames">
          {{ row.Cells[col].Data }}
        </td>
      </tr>
      </tbody>
    </table>

Of cause you can complicate column names and get object something like:

{
 columnName: 'Valid Date',
 dataKey: 'date_validite'
}

And loop thought array of such columns. This is up to you. I hope you catch the main idea.

Upvotes: 2

Related Questions