1

I have created an HTML table which will generate infinite columns based on the number of rows in the input data. I've tried to use this SO post as an example, but I'm struggling to convert my HTML to Angular Material design. Any suggestions?

StackBlitz demo

Since Angular material tables are column-based (and I couldn't find a way to iterate over the rows within them) I got stuck pretty quickly.

I couldn't get angular material tables working in the StackBlitz, so here is a copy paste of my code:

<table mat-table [dataSource]="newLicenseDS">

    <ng-container *ngFor="let disCol of newLicCol; let idx = index" matColumnDef="{{disCol}}">
        <th mat-header-cell *matHeaderCellDef>{{disCol}}</th>
        <ng-container *ngIf="idx==0">
           <td mat-cell *matCellDef="let e">{{e[0]|json}}</td>
        </ng-container>
        <ng-container *ngIf="idx==1">
           <td mat-cell *matCellDef="let e">{{e[1]|json}}</td>
        </ng-container>
        <ng-container *ngIf="idx==2">
           <td mat-cell *matCellDef="let e[2]">{{e|json}}</td>
        </ng-container>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="newLicCol"></tr>
    <tr mat-row *matRowDef="let row; columns: newLicCol"></tr>
</table>
Rilcon42
  • 9,584
  • 18
  • 83
  • 167
  • Why? Is this there any real reason? Performance will bite you. – Vova Bilyachat Aug 26 '19 at 00:36
  • It doesn't have to be infinite, but I can't tell how many columns there will be in advance, it's likely far less than a hundred columns, but I can't guarantee that, which is why I'm trying to write it this way – Rilcon42 Aug 26 '19 at 02:23

1 Answers1

2

the only thing you need is "loop" the matColumnDef. -see that we use [matColumnDef] and {{element[col]}}

If your table is like

<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">

  <ng-container *ngFor="let col of displayedColumns" [matColumnDef]="col">
    <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>

You only need transform your data and indicate the displayedColumns. You can do in a ngOnInit()

ngOnInit() {
    const head = this.data.map(x => x.name)
    const data: any[] = [];
    this.data.forEach((x, index) => {
      Object.keys(x).forEach((k, index2) => {
        data[index2] = data[index2] || {}
        data[index2][head[index]] = x[k]

      })
    })
    this.displayedColumns=head;
    this.dataSource = data.slice(1); //I remove the first element that was the "header"
  } 

See in stackblitz

Update about the question not use a mat-table else a simple table, just we need iterate using displayedColumns. Some like

<table>
  <tr>
    <th *ngFor="let col of displayedColumns">{{col}}</th>
  </tr>
  <tr *ngFor="let row of dataSource">
     <td *ngFor="let col of displayedColumns">{{row[col]}}</td>
  </tr>
</table>
Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • is it possible to do this without Angular Material ? I am using Angular 8 – Rishabh Aug 25 '21 at 11:57
  • 1
    @Rishabh, of course, you has yet the "displayedColumns" and the "dataSource". it's only iterate over this, I updated the answer (the stackblitz with the two models are in this one: https://stackblitz.com/edit/angular-8nmwlq-ixxajd?file=app%2Ftable-basic-example.html. NOTE: You can see the "data" using a `
    {{displayedColumns|json}}{{datasource|json}}
    ` to see how work
    – Eliseo Aug 25 '21 at 12:31
  • thanks for the reply, it works perfectly fine. But I have realised that this is not exactly what I am trying to do, my array is a simple string array and need to display it in 4xn way. 4 rows and n number of columns. I am trying how to move to a new column after the 4th element. I have been able to do this using ul li – Rishabh Aug 25 '21 at 13:59
  • 1
    @Rishabh, some like this [SO](https://stackoverflow.com/questions/68160729/angular-ngfor-four-elements-on-row/68164750#68164750)? – Eliseo Aug 25 '21 at 15:54
  • Yeah something like that Using ul li I am able to achieve this setting a height to the ul ngfor on li – Rishabh Aug 25 '21 at 16:11
  • the code in the SO only transform an array uni-dimensional in an array bi-dimensional, but I'm not pretty sure that can help you in case use ul and li :( – Eliseo Aug 25 '21 at 16:24