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