Dynamically render columns in Angular material table
Dharmen Shah
Posted on July 3, 2024
Did you know that you can dynamically render columns in #angular material table?
No, I am not talking about simply adding/removing columns on click of button, but a more robust solution like shown in below.
<table-basic-example>
<ng-container matColumnDef="boilingPoint">
<th mat-header-cell *matHeaderCellDef mat-sort-header="boilingPoint">
Boiling Point
</th>
<td mat-cell *matCellDef="let element">{{ element.boilingPoint }}</td>
</ng-container>
</table-basic-example>
As show in code above, it's upto consumer component which column it needs to render This technique involves mainly 2 things
1st is hostDirectives
- to attach MatSort
with component.
It is needed so that consumer can use mat-sort-header
if it wants
@Component({
selector: 'table-dynamic-example',
standalone: true,
imports: [MatTableModule, MatSortModule],
hostDirectives: [MatSort],
})
2nd is contentChildren
- to get projected columns
Due to internal structure of MatTable
, we can't directly use content projection here using ng-content
, hence contentChildren
is needed
private customCols = contentChildren(MatColumnDef);
And finally render them in afterViewInit
hook using MatTable.addColumnDef
Also make sure to attach host MatSort
with dataSource
's sort
. Otherwise sorting will not work
ngAfterViewInit() {
this.dataSource.sort = this.matSort;
this.customCols().forEach((col) => {
const columnName = col.name;
this.matTable()?.addColumnDef(col);
// need to wait until column is added
this.ngZone.onStable.pipe(take(1)).subscribe(() => {
this.columnsToDisplay.push(columnName);
});
});
}
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
@for (column of displayedColumns; track column) {
<ng-container [matColumnDef]="column">
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ column }}</th>
<td mat-cell *matCellDef="let element">{{ element[column] }}</td>
</ng-container>
}
<tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
<tr mat-row *matRowDef="let row; columns: columnsToDisplay;"></tr>
</table>
That's it! Full code is available on stackblitz
Posted on July 3, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.