KuluGary
KuluGary

Reputation: 141

Using Angular6 Mat-Table dynamically

I'm developing an Angular app which requires I display data which I retrieve from an API. Since I don't know exactly what data I would retrieve, and also this is a model I need to use for different tables, I need to make it both generate columns dynamically, but also fill every cell too.

The JSON I retrieve and I need to print in the table is similar to this:

[
    {
        "attributes": [],
        "brandReference": "f805a08df4c236ddb431e14a38419690",
        "computedPOS": "BEXFY_HEADQUARTERS",
        "deviceType": 1,
        "friendlyName": "BEXFY_TRANSPARENT_LED",
        "id": "953e9414d7a51e8-e0-681def0b02b5",
        "isMonitored": true,
        "location": "entrance",
        "posReference": "78fcef0f12993d52b2d2906dc4ce48d8",
        "timetable": [],
        "timezone": "Europe/Madrid"
    },
    {
        "attributes": [],
        "brandReference": "185fd549-4410-462b-a610-fe6b61c91cf6",
        "comments": "",
        "computedPOS": "BEXFY_HEADQUARTERS",
        "deviceType": 1,
        "friendlyName": "BEXFY_AUDIO_OFICINA",
        "id": "79eaa7f5f6603809-e0-681def0b0290",
        "location": "",
        "posReference": "78fcef0f12993d52b2d2906dc4ce48d8",
        "timetable": [],
        "timezone": "Europe/Madrid"
    },
    {
        "attributes": [],
        "brandReference": "185fd549-4410-462b-a610-fe6b61c91cf6",
        "comments": "",
        "computedPOS": "BEXFY_HEADQUARTERS",
        "deviceType": 1,
        "friendlyName": ".BEXFY_AUDIO_ADRI",
        "id": "97bf675e3e237bcd-e0-681def0b029f",
        "location": "",
        "posReference": "78fcef0f12993d52b2d2906dc4ce48d8",
        "timetable": [],
        "timezone": "Europe/Madrid"
    }
]

Please note that the object property keys could change, so I can't hardcode something like element.friendlyName. I receive which key names I should use through an array that looks like this.

["friendlyName", "computedPOS", "location"]

So in order to make it work, I made something like this.

<table mat-table [dataSource]="dataSource.data" class="mat-elevation-z8" style="width:90%;margin:0 auto;">

  <ng-container *ngFor="let column of modelCols; let colIndex = index" matColumnDef={{nameCols[colIndex]}}>
    <th mat-header-cell *matHeaderCellDef> {{nameCols[colIndex]}}</th>
    {{log(modelCols)}}
    <div *ngFor="let column of modelCols;">
      <td mat-cell *matCellDef="let element">
        {{log(element[column])}}
        {{element[column]}}
      </td>
    </div>

  </ng-container>

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

The problem with this, is that it results in a repeat of the first value ("friendlyName") over each column of the row. Something like this.

enter image description here

While the intended way of working is this:

enter image description here

Upvotes: 0

Views: 91

Answers (1)

nash11
nash11

Reputation: 8690

You need to be looping over nameCols to show your dynamic columns. Whatever columns your API asks you to show is all you need to iterate over to show your columns. Since you are using element[column] to display the item in the row. It will only display the needed item.

<ng-container *ngFor="let column of nameCols; let colIndex = index" [matColumnDef]="column">
    <th mat-header-cell *matHeaderCellDef>{{column}}</th>
    <td mat-cell *matCellDef="let element">{{element[column]}}</td>
</ng-container>

Here is a working example on StackBlitz with your data. This way even if a set of different columns comes from the API to display, all you need to do is update nameCols to display the right columns. The template will take care of the rest and show the associated data to the columns shown.

Upvotes: 1

Related Questions