I am building a table in Angular8 with Material table.
I am using an array of strings to define the displayedColumns and passing in each array value to the matColumnDef directive.
This is working properly.
TS
displayedColumns: any[] = ['username', 'firstname', 'lastname'];
HTML
<div class="table-container mat-elevation-z8">
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container *ngFor="let column of displayedColumns;" [matColumnDef]="column">
<th mat-header-cell *matHeaderCellDef> {{ column }} </th>
<td mat-cell *matCellDef="let element"> {{ element[column] }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
Question: Is it possible to define the displayedColumns as an array of objects rather than an array of strings?
I want to set a different value for the column display value, and also possibly set some other column properties conditionally.
Example: Notice the displayedColumns is an array of objects. This does NOT work.
TS
displayedColumns: any[] = [
{ name: 'username', display: 'User Name' },
{ name: 'firstname', display: 'First Name' },
{ name: 'lastname', display: 'Last Name' }
];
HTML
<div class="table-container mat-elevation-z8">
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container *ngFor="let column of displayedColumns;" [matColumnDef]="column.name">
<th mat-header-cell *matHeaderCellDef> {{ column.display }} </th>
<td mat-cell *matCellDef="let element"> {{ element[column.name] }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
Error message:
Could not find column with id "[object Object]".
at getTableUnknownColumnError (table.js:890)
at table.js:1973
I think the error indicates that the mat-table is iterating the displayedColumns, expecting an array element, but getting an object. Is there a way to fix this or another way to achieve this requirement?
I was able to achieve this by creating a separate object to store the table column name and display name.
// Table columns
initColumns: any[] = [
{
name: 'username',
display: 'User Name'
},
{
name: 'firstname',
display: 'First Name'
},
{
name: 'Description',
display: 'Description'
}
];
The displayedColumns is set to an array of strings for each column 'name' property.
// Displayed columns array of strings
displayedColumns: any[] = this.initColumns.map(col => col.name);
The ngFor iterates on the initColumns
array of objects and sets the matColumnDef, shows the display name and row values.
<ng-container [matColumnDef]="column.name" *ngFor="let column of initColumns;">
<th mat-header-cell *matHeaderCellDef> {{column.display}}</th>
<td mat-cell *matCellDef="let element"> {{element[column.name]}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
I got the idea from an answer to a similar question. Note that the trackbyindex
part was not required for my particular solution.