I have a component where I would like to display configurable html in the child component. Child components are not accessible to the client. So I think what I'm looking for is content projection
<Parent>
<ng-template #editTemplate> //custom
<button>Edit Me </button>
</ng-template>
<child1>
...
<child4>
I would like to show the #editTemplate here
</child4>
</child1>
</Parent>
so Inside of child4
I have this HTML
<div>
<ng-content #editTemplate></ng-content>
</div>
However I can't get the button to display. What am I doing wrong here?
CodePudding user response:
What you have here is an interesting combination of content projection and dependency injection.
<ng-template #editTemplate>
is being content-projected into Parent
component
<Parent>
<ng-template #editTemplate> <--- projected into <Parent>
<button>Edit Me </button>
</ng-template>
</Parent>
so Parent
has a direct reference to it via Content Child, if your Parent
component looks something like this:
@Component({
selector: 'parent',
template: `
<h2>Parent here!</h2>
<ng-content></ng-content> <--- #editTemplate will get projected here
<child1></child1>
`,
styles: [`h1 { font-family: Lato; }`],
})
export class ParentComponent {
@ContentChild('editTemplate') editTemplate: TemplateRef<any>; // <--- reference to #editTemplate
}
However, child4
is nested several layers deep, so dependency injection is your friend here, otherwise you would need to configure a reference in each layer to complete the chain from Parent
down to child4
.
Using DI, though, you can inject the Parent
component directly into child4
, who can then access the editTemplate
reference on the Parent
component instance and use *ngTemplateOutlet to insert the view from that TemplateRef
.
So child4
could look like this:
@Component({
selector: 'child4',
template: `
<h3>Child 4 here!</h3>
<div>And here's the injected template:</div>
<ng-container *ngTemplateOutlet="projectedTemplate"></ng-container> <--- use *ngTemplateOutlet to render editTemplate
`,
styles: [`h1 { font-family: Lato; }`],
})
export class Child4Component {
projectedTemplate: TemplateRef<any>;
constructor(private parentComponent: ParentComponent) {} // <-- inject ParentComponent instance
ngOnInit() {
this.projectedTemplate = this.parentComponent.editTemplate; // <-- set *ngTemplateOutlet to editTemplate
}
}
Here's a StackBlitz showing this approach.