I've created a custom TableComponent
which uses a @Directive
with ng-template
to define the columns. That's pretty flexible and abstracts away all the material stuff. So you can get a common table design all across your application. You just have to define everything once inside this component.
I'll include only the relevant parts.
The @Directive
is used to get a mapping between ng-template
and the Material Table column name.
@Directive({ selector: 'ng-template[rowColumn]' })
export class TableRowColumnDirective {
@Input() rowColumn: string;
constructor(public templateRef : TemplateRef<any>) { }
}
The @Component
fetches all ng-templates
and build a Map
to access the ng-templates
by their column names.
@Component({
selector: 'my-table',
templateUrl: './table.component.html'
})
export class TableComponent<T> {
@ContentChildren(TableRowColumnDirective) rowColumnDirectives: QueryList<TableRowColumnDirective>;
displayedColumns: ['foo', 'bar'];
// I use a Map here only, because it's much easier to access the
// provided ng-templates within table.component.html
rowColumnTemplates: Map<string, TableRowColumnDirective>;
ngAfterContentInit() {
// ArrayUtils.toMap is just a little helper function, which
// converts an array to a Map. In this case the value of
// `rowColumn` will become the key of the map
this.rowColumnTemplates = ArrayUtils.toMap(this.rowColumnDirectives.toArray(), val => val.rowColumn);
}
}
The @Component
's HTML simply adds mat-header-cell
and mat-cell
using an *ngFor
loop. The contents of the cells will then be filled with the provided ng-template
s.
<mat-table ...>
<ng-container *ngFor="let column of displayedColumns" [matColumnDef]="column">
<mat-header-cell *matHeaderCellDef>
HEADER CONTENT
</mat-header-cell>
<mat-cell *matCellDef="let row">
<ng-container [ngTemplateOutlet]="rowColumnTemplates.get(column).templateRef" [ngTemplateOutletContext]="{$implicit: row}"></ng-container>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
The table can then be used like this:
<my-table>
<!-- rowColumn matches the displayedColumns array -->
<ng-template rowColumn="foo" let-row>{{row.profile.type}}</ng-template>
<ng-template rowColumn="bar" let-customRowName>{{row.profile.status}}</ng-template>
</my-table>
Now you can add another @Directive
for the Header Column. In my provided example the Header will always be HEADER CONTENT
. It's basically just a copy of the TableRowColumnDirective
.
I know this isn't exactly what you were looking for, but I guess you can see how you can inject custom rows into a mat-table
. Take it as a starting point and I'm sure, you will be able to build a custom solution that fits your needs.