3

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 ...

asked Mar 23, 2024 at 22:51
5
  • turn the ng-template into its own component, and render it using its selector, or <ng-container *ngComponentOutlet="componentRef" /> Commented Mar 23, 2024 at 22:57
  • Otherwise, in test.ts, you need to get a reference with @ViewChild('content') content: TemplateRef. Then in A.ts you need to get a reference to test component which will then give you access to the template. Commented Mar 23, 2024 at 23:01
  • @GetOffMyLawn can you please explain your second comment a bit more? Commented Mar 23, 2024 at 23:10
  • It looks like what your trying to do is pass the template around to random components, and you cannot do that unless it is a component itself (first comment). What you need to do is create an input on A.ts that accepts a TemplateRef, then pass the template to that input. stackblitz.com/edit/… Commented Mar 23, 2024 at 23:19
  • @CodeontheRocks I tried your suggestion, but I am getting an error in TestComponent.ts that this.content does not exist in this.templateService.contentTemplate = this.content; Commented Mar 24, 2024 at 13:52

2 Answers 2

5

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.

answered Mar 24, 2024 at 0:44
Sign up to request clarification or add additional context in comments.

8 Comments

They are also very common for <div *ngIf="condition; then template1; else template2"></div> pre angular 17.
@Shlang I tried your first approach, neither I get an error, nor the Hello message is rendered. Regard to your second approach, I'm not sure how the child component gets the template, if the same as previously, i.e., via <ng-template [ngTemplateOutlet]="template"></ng-template> this also doesn't show the hello message.
@user6781 Have you added content input to your AComponent? And have you checked the linked playground? It may be better to see how it works altogether.
@Shlang I have added content/template like this: @Input() template!: TemplateRef<any>; is this correct? Your playground is a bit crowded, I couldn't follow!
Yes, that is correct. Ensure you imported NgTemplateOutlet to the component that uses [ngTemplateOutlet]. Other than that everything should work. If you could create a playground I would take a look.
|
1

Here's a quick solution that works for me (Angular 18)...

Define the template in its own component:

@Component({
 selector: 'app-hello-template',
 standalone: true,
 template: `
 <ng-template #helloTemplate let-name="name">
 <h1>Hello {{name}}.</h1>
 </ng-template>
 `
})
export class HelloTemplateComponent {
 // expose the template ref to hosts - may not needs static
 @ViewChild('helloTemplate', { static: true })
 templateRef!: TemplateRef<any>;
}

Then just include it and call it from the host component:

@Component({
 selector: 'app-test-template',
 standalone: true,
 imports: [
 HelloTemplateComponent,
 NgTemplateOutlet
 ],
 template: `
 <!-- add the template component - contains no non-template -->
 <!-- content so this will not render anything here -->
 <app-hello-template #templateComponent></app-hello-template>
 <!-- use it via the templateRef exposed from the template component -->
 <ng-container *ngTemplateOutlet="templateComponent.templateRef; context: { name: 'Alice' }"></ng-container>
 <ng-container *ngTemplateOutlet="templateComponent.templateRef; context: { name: 'Bob' }"></ng-container>
 `
})
export class TestTemplateComponent {
}
answered Jan 16, 2025 at 22:54

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.