I've a test component that receives an array of objects via @Input()
. I want to modify the data according to some internal logic / extra buttons but also allow the caller to decide how the data should be displayed.
Example of the component, with a trivial .toUpperCase()
to make user names uppercase:
@Component({
selector: 'test-component',
template: `
<h1>My Test</h1>
<ng-content></ng-content>
`
})
export class TestComponent implements OnInit {
@Input() data?: Array<{ name: string }>;
ngOnInit(): void {
this.data.map((item: any) => {
item.name = item.name.toUpperCase();
return item;
});
}
Now is there a way I can, in the projected content, access the data
that was provided to the component? Something like this:
<test-component [data]="[{name: 'joe'}, {name: 'mike'}]">
<p *ngFor="let person of data">{{ person.name }}</p>
</test-component>
This would be very helpful to, for example, build a component where I could project a table and use *ngFor
to render rows. The component itself would add pagination buttons and filter the data used by the *ngFor
accordingly.
Here is a solution for the problem.
Component:
@Component({
selector: 'test-component',
template: `
<h1>My Test</h1>
<ng-container
[ngTemplateOutlet]="template"
[ngTemplateOutletContext]=" {
data: this.data
}"
></ng-container>
`
})
export class TestComponent implements OnInit {
@Input() data?: Array<{ name: string }>;
@ContentChild(TemplateRef) template: TemplateRef<any> | null = null;
ngOnInit(): void {
this.data.map((item: any) => {
item.name = item.name.toUpperCase();
return item;
});
}
Usage:
<test-component [data]="[{name: 'joe'}, {name: 'mike'}]">
<ng-template let-data="data">
<p *ngFor="let person of data">{{ person.name }}</p>
</ng-template>
</test-component>