How can I render an <ng-template>
in different components. Let's say I have component test
as the following:
test.html
<ng-template #content >
<p> Hello world </p>
</ng-template>
test.ts
@Component({
selector: 'test',
templateUrl: './test.component.html',
standalone: true,
})
export class TestComponent implements OnInit {}
Now I want to render it in component A
. This is what I've tried (and many other more complicated versions that didn't work, so I keep the question with this simplest version):
A.html:
<test>
<ng-container *ngTemplateOutlet="content"></ng-container>
</test>
The error that I get is :
Property 'content' does not exist on type 'AComponent'.
<ng-container *ngTemplateOutlet="content"></ng-container>
I think this must be very simple to solve but I've checked the guideline in this post, this solution, and some other tutorials but none of them worked ...
While this is not very common, you can query TemplateRef
and use it as any other object - pass it as inputs, and share through services as long as an instance of the component that defines the template exists.
The most common scenario is passing TemplateRef
as input to a child component (it automatically ensures the template exists at the moment the child renders it) which renders it using NgTemplateOutlet
directive. Here is an example with the use of template reference variable:
// parent template
<ng-template #hello>Hello</ng-template>
<app-child [template]="hello"></app-child>
// child:
@Component({
selector: 'app-child',
standalone: true,
imports: [NgTemplateOutlet],
template: `<ng-template [ngTemplateOutlet]="template"></ng-template>`,
})
export class ChildComponent {
@Input() template?: TemplateRef<any>;
}
It is commonly used for implementing customizable components that work together and maintain parent-child relationships e.g. menus, tabs, and tree-views. You can find examples of using TemplateRef
as input in Material Tabs.
It is also possible to share it elsewhere as TemplateRef
can be accessed in the component via @ViewChild
:
@Component({
selector: 'app-template-definer',
standalone: true,
template: `<ng-template>Hello</ng-template>`,
})
export class TemplateDefinerComponent {
@ViewChild(TemplateRef) template!: TemplateRef<void>;
}
From here we can pass it to the child component as input or even can share via service. The latter would be considered an unsafe bad practice and has quite a lot of things to take into consideration before implementing this approach.
Please take a look at Playground which demonstrates how to share with children and globally.