Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are practical scenarios of *ngTemplateOutlet directive?

I was reading about *ngTemplateOutlet directive. The use of this directive is to instantiate a template dynamically by a template reference and context object as parameters.

What I want to know is that we have so many things in Angular to achieve the same results as *ngTemplateOutlet such as:

  1. We can have multiple *ngIf which could render different templates based on the component variable value within the same component. In a similar fashion we have [ngSwitch] which would render different templates for us based on different values.

  2. We could use references with *ngIf by referring to the template reference variable of the respective variable.

For the former case:

<div *ngIf="condition1"> Content 1 </div>
<div *ngIf="condition2"> Content 2 </div>
<div *ngIf="condition3"> Content 3 </div>

And for latter:

<ng-container *ngIf="condition then myTemplate else otherTemplate"></ng-container>
<ng-template #myTemplate> Some content... </ng-template>
<ng-template #otherTemplate> Some content... </ng-template>

If we have such methods in our arsenal what more value does *ngTemplateOutlet add?

What are the practical use cases (if there are any) where we cannot use the above methods and should use *ngTemplateOutlet directive or is it just another method to choose from to achieve the same result?

like image 845
patrick.1729 Avatar asked Oct 20 '18 18:10

patrick.1729


People also ask

What is the use of ngTemplateOutlet?

ngTemplateOutlet is a structural directive. We use it to insert a template (created by ngTemplate ) in various sections of our DOM. For example, you can define a few templates to display an item and use them display at several places in the View and also swap that template as per the user's choice.

What is the use of NG-container?

What is ng-container ? ng-container allows us to create a division or section in a template without introducing a new HTML element. The ng-container does not render in the DOM, but content inside it is rendered. ng-container is not a directive, component, class, or interface, but just a syntax element.

What is Templateref?

TemplateReflinkRepresents an embedded template that can be used to instantiate embedded views. To instantiate embedded views based on a template, use the ViewContainerRef method createEmbeddedView() .

What is the difference between Ng-content ng-container and ng-template?

To sum up, ng-content is used to display children in a template, ng-container is used as a non-rendered container to avoid having to add a span or a div, and ng-template allows you to group some content that is not rendered directly but can be used in other places of your template or you code.


3 Answers

Angular template outlets can be used to insert a common template in various sections of a view that are not generated by a loop or subject to a condition. For example, you can define a template for the logo of a company and insert it in several places in the page:

<div>
  <ng-container *ngTemplateOutlet="companyLogoTemplate"></ng-container>
  <h1>Company History</h1>
  <div>{{companyHistory}}</div>
</div>
<form (ngSubmit)="onSubmit()">
  <ng-container *ngTemplateOutlet="companyLogoTemplate"></ng-container>
  <h1>User info</h1>
  <label>Name:</label><input type="text" [(ngModel)]="userName" />
  <label>Account ID:</label><input type="text" [(ngModel)]="accountId" />
  <button>Submit</button>
</form>
<div class="footer">
  <ng-container *ngTemplateOutlet="companyLogoTemplate"></ng-container>
</div>

<ng-template #companyLogoTemplate>
  <div class="companyLogo">
    <img [src]="logoSourceUrl">
    <label>The ACME company, {{employeeCount}} people working for you!</label>
  </div>
</ng-template>

Templates and template outlets can also help to make a component configurable. The following example is taken from this article by Angular University.

A tab container component defines a default tab header template, but allows to override it with a custom template defined as an input property. The appropriate template (default or custom) is then inserted in the view with a template outlet:

@Component({
  selector: 'tab-container',
  template: `
    <ng-template #defaultTabButtons>
      <div class="default-tab-buttons">
        ...
      </div>
    </ng-template>
    <ng-container *ngTemplateOutlet="headerTemplate || defaultTabButtons"></ng-container>
    ... rest of tab container component ...
  `
})
export class TabContainerComponent {
    @Input() headerTemplate: TemplateRef<any>; // Custom template provided by parent
}

In the parent component, you define the custom tab header template and pass it to the tab container component:

@Component({
  selector: 'app-root',
  template: `      
    <ng-template #customTabButtons>
      <div class="custom-class">
        <button class="tab-button" (click)="login()">
          {{loginText}}
        </button>
        <button class="tab-button" (click)="signUp()">
          {{signUpText}}
        </button>
      </div>
    </ng-template>
    <tab-container [headerTemplate]="customTabButtons"></tab-container>      
  `
})
export class AppComponent implements OnInit {
  ...
}

You can see another advanced use case in this blog post by alligator.io.

like image 115
ConnorsFan Avatar answered Oct 04 '22 00:10

ConnorsFan


One thing that makes *ngTemplateOutlet more powerful than *ng-content is when you use it with [ngTemplateOutletContext] input. This enables you to create a totally unique template that can use state from within the component.

I have used this to create a select component that is uniquely styled per client, via different templates, but shares exactly the same code. Here is a StackBlitz link and also my article about it on indepth.dev.

One example of a benefit of *ngTemplateOutlets over using *ngIfs is that your component does not need to depend on external packages, i.e an Icon lib, if this is only going to be used by a single client.

like image 28
Stephen Cooper Avatar answered Oct 04 '22 00:10

Stephen Cooper


You have very valid question. If something can be achieved by simple if or switch case, why should we use *ngTemplateOutlet?

Independent Component

You are getting these thought because you are thinking about one independent Component level. In other words everything condition, templates are in the same component. We can easily select the template on the basis of certain condition.

Library Component

Dynamic Template

When I say Library Component, it means generic reusable component ex Autocompleter or Typeahead etc. These components provides the functional part however they allow the developer to choose their own template as per their needs.

Here is the catch now, these templates doesn't reside the Autocompleter, it comes from its @ContentChild.

ex:

<ng-autocompleter>
   <ng-template #item let-item>{{item.name}}</ng-template>
<ng-autocompleter>

In above example the <ng-template> is being defined the developer later point time and its not the direct part of <ng-autocompleter>.

Template Context

Template context is very important whenever highly configured component is developed. Getting the dynamic template (html) is not good enough to serve the purpose. We need to bind the value to the ng-template. Since ng-template is not in the part of ng-autocompleter we need to pass the context which contains all necessary data to bind.

ex : In above case if you see we declared the item variable by let-item but where is item is coming from. That will be decided by the context given to *ngTemplateOutlet.

One line conclusion If we want to inject the templates which is will be declared in future by someone, I cannot handle this case by *ngIf or *ngSwitch. We need to use *ngTemplateOutlet.

like image 21
Sunil Singh Avatar answered Oct 04 '22 00:10

Sunil Singh