Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Content projection inside angular-material table

Instead of a regular way of displaying data to table. I'm trying to create my custom-table component and project the data in the material table via .

like this:

<table mat-table [dataSource]="dataSource">
	<!-- I want to Render the header and cell data here -->
	<ng-content></ng-content>
	
	<mat-header-row *matHeaderRowDef="headers; sticky: true"></mat-header-row>
	<mat-row *matRowDef="let row; columns: headers;"></mat-row>
</table>

So I can call this customized component like this:

<app-customized-table>
	<ng-container matColumnDef="id">
		<mat-header-cell *matHeaderCellDef> Id </mat-header-cell>
		<mat-cell *matCellDef="let element"> {{element.Id}} </mat-cell>
	</ng-container>
	...etc
</app-customized-table>

However, it won't detect the content. Here's a stackblitz example that i'm trying to do.

https://stackblitz.com/edit/angular-qwvcln?file=src%2Fapp%2Fcustom-table.component.ts

Is there a way to do this?

Thanks.

like image 767
jedion Avatar asked Nov 16 '18 10:11

jedion


People also ask

What is projected content in angular?

Content projection is a pattern in which you insert, or project, the content you want to use inside another component. For example, you could have a Card component that accepts content provided by another component. With this type of content projection, a component accepts content from a single source.

How do you style content that was projected using NG content?

If you want to style the projected content within <ng-content>, you can do so using :host and ::ng-deep to apply styling to all nested elements within the <contact> component.

What is MatTableDataSource?

By default, the MatTableDataSource sorts with the assumption that the sorted column's name matches the data property name that the column displays. For example, the following column definition is named position , which matches the name of the property displayed in the row cell.

How do you use Ngcontent?

The ng-content is used when we want to insert the content dynamically inside the component that helps to increase component reusability. Using ng-content we can pass content inside the component selector and when angular parses that content that appears at the place of ng-content.


1 Answers

Bit late to the party, but I had the same challenge and was able to solve it as follows:

You can solve it by adding the column definitions to the table programmatically, by using the @ContentChildren and @ViewChild functionality:

your template file (e.g. customized-table.component.html):

<table mat-table [dataSource]="dataSource">
    <ng-content></ng-content>

    <mat-header-row *matHeaderRowDef="headers; sticky: true"></mat-header-row>
    <mat-row *matRowDef="let row; columns: headers;"></mat-row>
</table>

your codebehind (e.g. customized-table.component.ts):

@Component({
    selector: 'app-customized-table',
    templateUrl: './customized-table.component.html'
})
export class CustomizedTableComponent<T> implements AfterContentInit {
    constructor() { }

    @Input() dataSource: T[]; // or whatever type of datasource you have
    @Input() headers: string[];

    // this is where the magic happens: 
    @ViewChild(MatTable, { static: true }) table: MatTable<T>;
    @ContentChildren(MatColumnDef) columnDefs: QueryList<MatColumnDef>;

    // after the <ng-content> has been initialized, the column definitions are available.
    // All that's left is to add them to the table ourselves:
    ngAfterContentInit() {
        this.columnDefs.forEach(columnDef => this.table.addColumnDef(columnDef));
    }
}

Now, you're able to use:

<app-customized-table [headers]="headers">
    <ng-container matColumnDef="id">
        <mat-header-cell *matHeaderCellDef> Id </mat-header-cell>
        <mat-cell *matCellDef="let element"> {{element.Id}} </mat-cell>
    </ng-container>
    ...etc
</app-customized-table>

Stackblitz working demo with lazy loaded modules

like image 66
yaba Avatar answered Sep 20 '22 14:09

yaba