How To Use ngTemplateOutlet In Angular

How To Use ngTemplateOutlet In Angular

In this article, we will learn how to use ngTemplateOutlet Angular. A directive is ngTemplateOutlet. It uses a template reference and a context object as arguments to dynamically create a template. We'll show you a few ngTemplateOutlet examples to get you started.

What is ngTemplateOutlet?

The structural directive ngTemplateOutlet is used to create a template. It's used to insert a template (generated by ngTemplate) into various DOM areas. For example, you can define a few templates to display an item and use them to display it in multiple locations across the View, as well as change the template based on the user's preference.

How to use ngTemplateOutlet

Let's start with a very basic ngTemplateOutlet example.

The ng-template is used to define a template in the following code. The Template reference variable stores the template's reference. (TemplateRef).

The template is not self-rendering. To render it, we'll need to employ a structural directive. ngTemplateOutlet accomplishes this.

The Template Reference directive is passed to the ngTemplateOutlet directive. The template is rendered. Any inside content encapsulated by ngTemplateOutlet will not be rendered.

<h3>Example 1</h3>
 
<!--  This is our template. template1 is the template reference variable holds the reference to the Template
  template1 is of type TemplateRef This won't be rendered here -->
 
 
<ng-template #template1>  
  <p>This is our template. It will be displayed on the div *ngTemplateOutlet="myTemplateRef"</p>
</ng-template>
 
<p>The Template appears after this</p>
 
 
<!-- 
  We want to render the above template here.
  Hence we use the ngTemplateOutlet directive 
  Assign template1 to ngTemplateOutlet
-->
 
 
<ng-container *ngTemplateOutlet="template1">
  This text is not displayed
</ng-container> 
 
 
<!-- 
  Use can use any element. 
  Here we use div instead of ng-container
  Div is not rendered 
-->
 
 
<div *ngTemplateOutlet="template1">
</div> 

The div in the following code is not rendered.

<div *ngTemplateOutlet="template1">
</div> 

i.e., because the angular transforms the preceding into the ng-template syntax. The ngTemplateOutlet renders the template pointed by template1 by replacing everything inside the ng-template element.

<ng-template [ngTemplateOutlet]="template1">
  <div></div>
</ng-template>

The use case presented above is straightforward. You can do the same thing with the ngIf and ngSwitch directives. Using the ngContent, you can also employ content projection.

Passing data to ngTemplateOutlet

We can also use its second property, ngTemplateOutletContext, to give data to it.

The code below builds a template. It's called messageTemplate. The let-value command creates a local variable named value.

<ng-template let-value="value" #messageTemplate>  
    <p>Value Received from the Parent is  {{value}}</p>
</ng-template>

Using the ngTemplateOutletContextproperty, we can provide any value to the value.

<ng-container [ngTemplateOutlet]="messageTemplate" 
       [ngTemplateOutletContext] ="{value:'1000'}">
</ng-container>  

You can also use the following syntax as an alternative.

<ng-container *ngTemplateOutlet="messageTemplate; context:{value:100}">
</ng-container> 

Pass more than one value.

<ng-template let-name="nameVar" let-message="messageVar" #template3>  
  <p>Dear {{name}} , {{message}} </p>
</ng-template>

<ng-container [ngTemplateOutlet]="templates" 
          [ngTemplateOutletContext] ="{nameVar:'Guest',messageVar:'Welcome to our site'}">
</ng-container> 

Pass an object.

<ng-template let-person="person"  #template4>  
  <p>Dear {{person.name}} , {{person.message}} </p>
</ng-template>

<ng-container [ngTemplateOutlet]="templates" 
           [ngTemplateOutletContext] ="{ person:{name:'Guest',message:'Welcome to our site'} }">
</ng-container> 

Using $implicit

If you use the context object's key $implicit, it will set its value as default for all local variables.

For example, because we haven't given the let-name any value, it will use the value from the $implicit, which is Guest.

<ng-template let-name let-message="message" #template3>  
  <p>Dear {{name}} , {{message}} </p>
</ng-template>
 
<ng-container [ngTemplateOutlet]="templates" 
              [ngTemplateOutletContext] ="{$implicit:'Guest',message:'Welcome to our site'}">
</ng-container> 

In the following code, the value for both name and message is obtained from the $implicit, i.e. Guest.

<ng-template let-name let-message #template3>  
  <p>Dear {{name}} , {{message}} </p>
</ng-template>
 
 
<ng-container [ngTemplateOutlet]="template3" 
      [ngTemplateOutletContext] ="{$implicit:'Guest',message:'Welcome to our site'}">
</ng-container> 

Passing Template to a Child Component

From the parent component, we can pass the complete template to a child component. The method is similar to that of sending data from a parent component to a child component.

Make a component that serves as a parent. Create a ng-template with the name #parentTemplate.

Using property binding, pass the parentTemplate to the child component. (<child [customTemplate] = "parentTemplate" ></child>)

import { Component, TemplateRef, Input } from '@angular/core';
 
@Component({
  selector: 'parent',
  template: `
  
  <h1>Parent component</h1>
  <ng-template #parentTemplate>  
    <p>
      This Template is defined in Parent. 
      We will send it to child component
    </p>
  </ng-template>
 
  <child [customTemplate]="parentTemplate"></child>
  `
})
export class ParentComponent {
  
}

Components in the Child receive the parentTemplate via @Input(). After that, you should provide it to ngTemplateOutlet.

@Component({
  selector: 'child',
  template: `
  <h2>Child component</h2>
 
  <ng-container *ngTemplateOutlet="customTemplate">
  </ng-container> 
  `
})
export class ChildComponent {
 
  @Input() customTemplate: TemplateRef<HTMLElement>;
 
}

Using ViewChild to Access the template

To gain access to the component's parentTemplate, use the ViewChild.

import { Component, TemplateRef, Input, OnInit, ViewChild, AfterViewInit } from '@angular/core';
 
@Component({
  selector: 'parent',
  template: `
  
  <h1>Parent component</h1>
  <ng-template #parentTemplate>  
    <p>
      This Template is defined in Parent. 
      We will send it to child component
    </p>
  </ng-template>
 
  <child [customTemplate]="parentTemplate"></child>
  
  `
})
export class ParentComponent implements OnInit, AfterViewInit {
 
  @ViewChild('parentTemplate',null) myTemplate:TemplateRef<HTMLElement>;
  
  ngAfterViewInit() {
    console.log(this.myTemplate)
  }
 
}

Content Projection and ngTemplate

Both the content projection and the ngTemplate can be combined.

The Parent component, which uses the content projection to pass a template to the child, is shown below.

import { Component, TemplateRef, Input, OnInit, ViewChild, AfterViewInit } from '@angular/core';
 
@Component({
  selector: 'parent1',
  template: `
  
  <h1>Parent Component </h1>
 
  <child1> 
    <p>This Template is Projected to the Child</p>
  </child1>
  `
})
export class Parent1Component {
}

We put it in a ngTemplate in the child.

import { Component, TemplateRef, Input, OnInit, ViewChild, AfterViewInit } from '@angular/core';
 
@Component({
  selector: 'child1',
  template: `
 
  <h1>Child Component </h1>
 
  <ng-template #parentTemplate>
    <ng-content></ng-content>
  </ng-template>
 
  <ng-template [ngTemplateOutlet]="parentTemplate"></ng-template>
 
  `
})
export class Child1Component {
}

ngTemplateOutlet Example

The software we're making will display items in either a card or a list format.

Make a fresh application. Open the app.component.html file in your browser.

First, we inquire about the user's preferred display mode. Using the select option dropdown, he must select from the card and list.

<label for="mode">Display Mode:</label>
<select [(ngModel)]="mode">
  <option *ngFor="let item of modeOptions" [ngValue]="item.mode">{{item.mode}}</option>
</select>

Make a template for the card display next. CardTemplate is the name you should give it. Items are input into the template. To show the item header and content in a card format, loop through the items collection using the ngFor.

<ng-template let-items #cardTemplate>
  <div *ngFor="let item of items">
    <h1>{{item.header}}</h1>
    <p>{{item.content}}</p>
  </div>
</ng-template>

The ul is used by the listTemplate to display the elements in a list manner.

<ng-template let-items #listTemplate>  
  <ul>
    <li *ngFor="let item of items">
      <strong>{{item.header}} </strong> ( {{item.content}} )
    </li>
  </ul>
</ng-template>

Finally, the items are passed to the item-view component. We also provide it the template.

<item-view [itemTemplate]="template" [items]="items">
</item-view>


To begin, use the ViewChild to obtain a reference to both the template and the child.

Now open the app.component.ts and put the following code:

@ViewChild('cardTemplate',null) cardTemplate:TemplateRef<HTMLElement>;
@ViewChild('listTemplate',null) listTemplate:TemplateRef<HTMLElement>;

Define the items, mode, and modeOptions variables.

mode ="card"

 items = [
   {
     header: 'Angular article',
     content: 'The Angular article for Beginners & Professionals'
   },
   {
     header: 'Typescript article',
     content: 'The Complete Guide to Typescript'
   },
   {
     header: 'Entity Framework Code article',
     content: 'Learn Everything about Entity Framework Core'
   },
 ];

 modeOptions = [
   { mode: "card" },
   { mode: "list" },
 ];

Depending on the option of mode, the template returns either a listTemplate or a cardTemplate.

get template() {

  if(this.mode=="list") return this.listTemplate
  return this.cardTemplate
}

From the parent component, the ItemViewComponent receives the items to display and the itemTemplate to use.

@Input() items: any[] = [];
@Input() itemTemplate: TemplateRef<HTMLElement>;

Please pass the item on. To display the item, send a template to the ngTemplateOutlet. To pass the items collection, use the ngTemplateOutletContext.

<ng-container [ngTemplateOutlet]="itemTemplate" [ngTemplateOutletContext]="{$implicit:items}">
</ng-container> 

The following code is the complete source code of the example.

The code of the app.component.ts file:

import { Component, TemplateRef, ViewChild } from '@angular/core';
 
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'ngTemplateOutlet Example';
 
  @ViewChild('cardTemplate',null) cardTemplate:TemplateRef<HTMLElement>;
  @ViewChild('listTemplate',null) listTemplate:TemplateRef<HTMLElement>;
 
  mode ="card"
 
  items = [
    {
      header: 'Angular article',
      content: 'The Angular article for Beginners & Professionals'
    },
    {
      header: 'Typescript article',
      content: 'The Complete Guide to Typescript'
    },
    {
      header: 'Entity Framework Code article',
      content: 'Learn Everything about Entity Framework Core'
    },
  ];
 
  modeOptions = [
    { mode: "card" },
    { mode: "list" },
  ];
 
  get template() {
 
    if(this.mode=="list") return this.listTemplate
    return this.cardTemplate
  }
 
}

The code of the app.component.html file:

<h1>ngTemplateOutlet Example</h1>
 
<label for="mode">Display Mode:</label>
<select [(ngModel)]="mode">
  <option *ngFor="let item of modeOptions" [ngValue]="item.mode">{{item.mode}}</option>
</select>
 
<ng-template let-items #cardTemplate>
  <div *ngFor="let item of items">
    <h1>{{item.header}}</h1>
    <p>{{item.content}}</p>
  </div>
</ng-template>
 
<ng-template let-items #listTemplate>  
  <ul>
    <li *ngFor="let item of items">
      <strong>{{item.header}} </strong> ( {{item.content}} )
    </li>
  </ul>
</ng-template>
 
<item-view [itemTemplate]="template" [items]="items">
</item-view>

The code of the item-view.component.ts:

import { Component, Input, TemplateRef } from '@angular/core';
 
 
@Component({
  selector: 'item-view',
  template: `
  <h2>Item View</h2>
 
  <ng-container [ngTemplateOutlet]="itemTemplate" [ngTemplateOutletContext]="{$implicit:items}">
  </ng-container> 
  `
})
export class ItemViewComponent {
 
  @Input() items: any[] = [];
  @Input() itemTemplate: TemplateRef<HTMLElement>;
 
}

The code of the app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule} from '@angular/forms';
 
import { AppComponent } from './app.component';
import { ItemViewComponent } from './item-view.component';
 
@NgModule({
  declarations: [
    AppComponent,
    ItemViewComponent
  ],
  imports: [
    BrowserModule,FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Conclusion

In this article, we learned how to use ngTemplateOutlet in Angular using examples.

I hope this article helps you and you will like it.👍

If you have any doubt or confusion then free to ask in the comment section.

Post a Comment

Previous Post Next Post