How To Use ng-template & TemplateRef In Angular

How To Use ng-template & TemplateRef In Angular

In this article, we will learn what is ng-template and TemplateRef and how to use them in angular. We'll also learn how it works and how Angular uses it in directives like ngIfngFor, and ngSwitch, among others. To display dynamic templates, we can use ng-template with ngTemplateOutlet, which is covered in a different article.

What is ng-Template?

The template is contained in the <ng-template> Angular element. An HTML snippet is what a template is. On the DOM, the template does not render itself.

Create a new Angular Application and paste the following code into app.component.html to see how it works.

<h2>Defining a Template using ng-Template</h2>
 
<ng-template>
  <p> Say Hello</p>
</ng-template>

The outcome of the code above is as follows. Say Hello is not rendered by Angular. It's not even listed in the DOM as a hidden element.

//output
 
Defining a Template using ng-Template

ng-template only defines a template, for example. It's our duty to tell angular where to put it and when to show it.

The template can be displayed in a few different ways.
  1. The ngTemplateOutlet directive is used.
  2. The TemplateRef and ViewContainerRef are used in this example.

Displaying the Template

ngTemplateOutlet

The template is rendered via the ngTemplateOutlet structural directive.

We must first generate the template and assign it to a template reference variable before we can use this directive (sayHelloTemplate in the following template).

<h1>ng-template & TemplateRef</h1>
 
<h2>Using the ngTemplateOutlet</h2>
 
 
<ng-template #sayHelloTemplate>
  <p> Say Hello</p>
</ng-template>

In the DOM, where we wish to render the template, we use the ngTemplateOutlet.

The following code assigns the Template variable sayHelloTemplate to the ngTemplateOutlet directive using the Property Binding.

<ng-container *ngTemplateOutlet="sayHelloTemplate">
  This text is not displayed
</ng-container> 

//Output
ng-template & TemplateRef
Using the ngTemplateOutlet
Say Hello

The ngTemplateOutlet directive's content is not displayed. It takes content from the sayHelloTemplate and replaces it.

TemplateRef & ViewContainerRef

What is TemplateRef?

TemplateRef is a class that allows you to refer to an ng-template from within a component or directive class. We can manipulate the template from component code by using TemplateRef.

Remember that ng-template is a collection of HTML tags contained within the ng-template> HTML element.

<ng-template>
  <p> Say Hello</p>
</ng-template>

We must first provide a template reference variable to the above ng-template in order to access it in the component or directive. In the code below, the variable #sayHelloTemplate is used.

<ng-template #sayHelloTemplate>
  <p> Say Hello</p>
</ng-template>

Now we can use the ViewChild query to inject the sayHelloTemplate as an instance of the class TemplateRef into our component.

@ViewChild('sayHelloTemplate', { read: TemplateRef }) sayHelloTemplate:TemplateRef<any>;

Now we must tell Angular where it should render it. Use the ViewContainerRef to accomplish this.

The ViewContainerRef is identical to the TemplateRef in appearance. Both include a reference to a section of the view.
  • The TemplateRef contains the ng-template reference template.
  • When injected via DI, ViewContainerRef holds a reference to the host element that hosts the component (or directive).
We may use the createEmbeddedView function to add the template to the component once we have ViewContainerRef.

constructor(private vref:ViewContainerRef) {
}

ngAfterViewInit() {
  this.vref.createEmbeddedView(this.sayHelloTemplate);
}

The template is located at the bottom of the page.

Angular makes heavy use of ngTemplate in its structural directives. However, it conceals its intricacies from us.

ng-template with ngIf

You've probably used ngIf quite a bit. Here's how we put it to use. Before ngIf, we use a *.

<label>
  <input [(ngModel)]="selected" type="checkbox">Select Me
</label>
 
<div *ngIf="selected">
  <p>You are selected</p>
</div>

There's another method to write the code above. That's the ng-template syntax in action. To do so, follow the steps below.
  1. ngIf is bound to a new element called ng-template.
  2. Instead of *ngIf="selected," use the property binding syntax [ngIf]="selected."
  3. Inside the ng-template, move the div element on which ngIf is attached.

<label>
  <input [(ngModel)]="selected" type="checkbox">Select Me
</label>
 
<ng-template [ngIf]="selected">
  <div>
    <p>You are selected</p>
  </div>
</ng-template>

The code behaves in the same way as a standard *ngIf.

Angular converts every *ngIf to ng-template Syntax behind the scenes. Every structural directive, such as ngFor, ngSwitch, ngTemplateOutlet, and so on, accomplishes this.

How it works

Let's have a look at the ttIf directive, which we developed in the lesson custom structural directive, to see how structural directives with ng-template function. The ttIf directive is a simplified version of the *ngIf directive.

Add the following code to the tt-if.directive.ts file. Remember to declare ttIfDirective in app.module.ts as well.

import { Directive, ViewContainerRef, TemplateRef, Input } from '@angular/core';
 
@Directive({ 
  selector: '[ttIf]' 
})
export class ttIfDirective  {
 
  _ttif: boolean;
 
  constructor(private _viewContainer: ViewContainerRef,
              private templateRef: TemplateRef<any>) {
  }
 
 
  @Input()
  set ttIf(condition) {
    this._ttif = condition
    this._updateView();
  }
 
  _updateView() {
    if (this._ttif) {
      this._viewContainer.createEmbeddedView(this.templateRef);
    }
    else {
      this._viewContainer.clear();
    }
  }
 
}

Open the app.component.html file in your browser. Both div <*ttIf="selected"> and <ng-template [ttIf]="selected"> syntax can be used.

Show/hide 
<input type="checkbox" [(ngModel)]="selected">
 
<div *ttIf="selected">
  Using the ttIf directive via *ttIf
</div>
 
 
<ng-template [ttIf]="selected">
  <div>
    <p>Using the ttIf directive via ng-template</p>
  </div>
</ng-template>

Add the following code under the app.component.ts:

import { Component } from '@angular/core';
 
@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  selected=false;
}

Let's have a look at the directive code now. In the constructor, we inject ViewContainerRef and TemplateRef instances.

constructor(private _viewContainer: ViewContainerRef,
	private templateRef: TemplateRef<any>) {
}

In the last section, we looked at ViewContainerRef. It contains a reference to the host element, which is where our directive is hosted.

We got the reference to the template using the ViewChild in the previous example. However, this is not possible in this location. As a result, we use the TemplateRef DI token from Angular Dependency Injection to inject the template into our directive.

When the condition is true, the Template is placed into the DOM. The ViewContainerRef's createEmbeddedView function is used to do this. The clean command removes the template from the document object model (DOM).

this._viewContainer.createEmbeddedView(this.templateRef);

Multiple Structural Directives

Multiple Structural Directives cannot be assigned to a single ng-template.

For example, if you use ngIf and ngFor on the same div, you'll get a template parse problem.

<div *ngIf="selected"
     *ngFor="let item of items">
        {{item.name}}
</div>


Uncaught Error: Template parse errors:

Can't have multiple template bindings on one element. Use only one attribute named 'template' or prefixed with *

As illustrated below, you may use ng-container to surround one directive with another.

<ng-container *ngIf="selected">
  <div *ngFor="let item of items">
       {{item.name}}
  </div>
</ng-container>

ng-template with ngIf, then & else

The ng-template is demonstrated using the ngIf, then, and else example in the following code.

The ng-template specifies the template for the if, then, and else clauses. To acquire the reference to those blocks, we use the template reference variable.

We specify the template to render in the *ngIf condition by pointing to the template variable in the then & else condition.

<h2>Using ngTemplate with ngIf then & else</h2>
 
<div *ngIf="selected; then thenBlock1 else elseBlock1">
  <p>This content is not shown</p>
</div>
 
<ng-template #thenBlock1>
  <p>content to render when the selected is true.</p>
</ng-template>
 
<ng-template #elseBlock1>
  <p>content to render when selected is false.</p>
</ng-template>

The ng-template syntax can be used to create the above ngif.

<ng-template [ngIf]="selected" [ngIfThen]="thenBlock2" [ngIfElse]="elseBlock2">
  <div>
    <p>This content is not shown</p>
  </div>
</ng-template>
 
<ng-template #thenBlock2>
  <p>content to render when the selected is true.</p>
</ng-template>
 
<ng-template #elseBlock2>
  <p>content to render when selected is false.</p>
</ng-template>

ng-template with ngFor

The following is an example of a ngFor directive.

<ul>
   <li *ngFor="let movie of movies; let i=index; let even=even;trackBy: trackById">
     {{ movie.title }} - {{movie.director}}
   </li>
</ul>

is written using the ng-template syntax as follows:

<ul>
<ng-template 
   ngFor let-movie [ngForOf]="movies" 
   let-i="index" 
   let-even="even"
   [ngForTrackBy]="trackById">
 
   <li>
     {{ movie.title }} - {{movie.director}}
   </li>
 
</ng-template>
</ul>

ng-template with ngSwitch

ngSwitch is demonstrated in the following example.

<input type="text" [(ngModel)]="num">
 
<div [ngSwitch]="num">
  <div *ngSwitchCase="'1'">One</div>
  <div *ngSwitchCase="'2'">Two</div>
  <div *ngSwitchCase="'3'">Three</div>
  <div *ngSwitchCase="'4'">Four</div>
  <div *ngSwitchCase="'5'">Five</div>
  <div *ngSwitchDefault>This is Default</div>
</div>

The ng-template is used with ngSwitch in the example above. It's worth noting that while ngSwitch isn't a structural directive, ngSwitchCase and ngSwitchDefault are.

<div [ngSwitch]="num">
  <ng-template [ngSwitchCase]="'1'">
    <div>One</div>
  </ng-template>
  <ng-template [ngSwitchCase]="'2'">
    <div>Two</div>
  </ng-template>
  <ng-template [ngSwitchCase]="'3'">
    <div>Three</div>
  </ng-template>
  <ng-template [ngSwitchCase]="'4'">
    <div>Four</div>
  </ng-template>
  <ng-template [ngSwitchCase]="'5'">
    <div>Five</div>
  </ng-template>
  <ng-template ngSwitchDefault>
    <div>This is default</div>
  </ng-template>
</div>

Conclusion

In this article, we covered what is ng-template and TemplateRef and how to use them in angular. We also learned how it works and how Angular uses it in directives like ngIfngFor and ngSwitch among others.

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