Search code examples
angularmat-table

Render a map object (with dynamic keys and values) into angular mat-table (columns and rows as keys and values of the map)


I am developing a POC using angular8 as frontend and SpringBoot as backend. My backend function returns me a List of Map objects (List < Map < String, Object > >) which has dynamic keys and values. I need to use this map array in frontend angular using mat-table inside mat-dialog-content. I'm stuck on defining the keys and values as the required attributes for the mat table. Please help me in populating the dynamic list of map objects (column headers as map key, and row as map value).

Posted my component and html files below:

component:

export class ProfileDialogComponent {
  username: String = "";
  mapArray: Map < String, Object > [] = [];
  constructor(private dialogRef: MatDialogRef < ProfileDialogComponent > ,
    @Inject(MAT_DIALOG_DATA) data, private userService: UserService) {
    this.username = data.username;
    this.userService.getImportedUserCareer(this.username).subscribe(data => {
      this.mapArray = data;
    });
  }
}

html:

<div>
  <mat-dialog-content *ngFor="let map of mapArray">
    <mat-table class="mat-elevation-z8" [dataSource]="map">

      <ng-container matColumnDef="column" *ngFor="let column of map | keyvalue">
        <mat-header-cell *matHeaderCellDef>{{column}}</mat-header-cell>
        <mat-cell *matCellDef="let element">{{element[column]}}</mat-cell>
      </ng-container>
      <mat-header-row *matHeaderRowDef="map"></mat-header-row>
      <mat-row *matRowDef="let row; columns: map"></mat-row>
    </mat-table>
  </mat-dialog-content>
</div>

At this point I'm getting the following error: Error: Duplicate column definition name provided: "column".

I have the map array populated in my component with map of string and string values. But the implementation logic in html is not complete, it would be really helpful if somebody can guide me how to populate the map data in mat table.

PS: I have iterated the map array in mat-dialog-content so that I get each map object in mat-table, so that the map keys and values should be populated as each mat-table column headers and rows inside each mat-dialog-content.

Below is a sample of the data

[
  {
    "Test Matches": 320,
    "Runs": 17500,
    "High Score": 242,
    "Batting Avg": 65.42,
    "Wickets": 14,
    "Bowling Avg": 31.76,
    "Best Bowling": "1/34",
    "Catches": 173,
    "MoS": 25
  },
  {
    "ODI Matches": 150,
    "Runs": 15750,
    "High Score": 184,
    "Batting Avg": 62.75,
    "Catches": 173,
    "MoM": 54
  }
]

Please help!

Thanks, Shihad


Solution

  • The following template should work for you:

    <div *ngFor="let map of mapArray">
      <mat-table class="mat-elevation-z8" [dataSource]="[map]">
        <ng-container [matColumnDef]="column.key" *ngFor="let column of map | keyvalue">
          <mat-header-cell *matHeaderCellDef>{{ column.key }}</mat-header-cell>
          <mat-cell *matCellDef="let element">{{ column.value }}</mat-cell>
        </ng-container>
        <mat-header-row *matHeaderRowDef="({}).constructor.keys(map)"></mat-header-row>
        <mat-row *matRowDef="let row; columns: ({}).constructor.keys(map)"></mat-row>
      </mat-table>
    </div>
    

    Stackblitz Example

    Note that for better performance you can replace ({}).constructor.keys(map) with your own custom pipe like map | keys where pipe is:

    @Pipe({ name: 'keys' })
    export class EnumToArrayPipe implements PipeTransform {
      transform(data: {}) {
        return Object.keys(data);
      }
    }