I have angular components, where I'm projecting one component into another via content. For example:
app-component-a-controls
is projected into app-component-a
. app-component-a
draws several app-component-a-controls
via *ngFor
.
app-component-a
HTML:
<app-component-a>
<app-component-a-controls>
<button (click)="log(record)">Click Me!</button>
</app-component-a-controls>
</app-component-a>
app-component-a-controls
HTML:
<... *ngFor="...">
<ng-content select="app-component-a-controls"></ng-content>
</...>
I need somehow to access items outside, for example when I click button Click Me!
, I need to get ngFor corresponding item as parameter called record
. Something like the following:
<app-component-a>
<app-component-a-controls let-record>
<button (click)="log(record)">Click Me!</button>
</app-component-a-controls>
</app-component-a>
Any ideas, how can I achieve it?
CodePudding user response:
You can pass your button
through an @Input()
of <app-component-a-controls>
as a TemplateRef
.
So you app component template would look something like this....
app.component.html
<app-component-a>
<app-component-a-controls [buttonTemplate]="buttonTemplateExample"></app-component-a-controls>
<ng-template let-record="record" #buttonTemplateExample>
<button (click)="log(record)">Click Me!</button>
</ng-template>
</app-component-a>
Notice the let-record="record"
on the ng-template
which we declare as a template variable that will be resolved when we render the template in the app-component-a-controls
component.
Then in your app-component-a-controls
template render the button template using ng-container
with [ngTemplateOutlet]
and then use [ngTemplateOutletContext]
to pass a "record" value to our template...
app-component-a-controls.component.html
<div *ngFor="let control of controls">
{{ control.label }}
<ng-container
[ngTemplateOutlet]="buttonTemplate"
[ngTemplateOutletContext]="{ record: control.record }">
</ng-container>
</div>
app-component-a-controls.component.ts
import { Component, Input, OnInit, TemplateRef } from '@angular/core';
@Component({
selector: 'app-component-a-controls',
templateUrl: './component-a-controls.component.html',
styleUrls: ['./component-a-controls.component.css'],
})
export class ComponentAControlsComponent implements OnInit {
@Input()
public buttonTemplate: TemplateRef<any>;
public controls: any[] = [
{
label: 'ControlA',
record: 'This is the value for Control A',
},
{
label: 'ControlB',
record: 'This is the value for Control B',
},
];
constructor() {}
ngOnInit() {}
}
I put together a working stackblitz of this approach...