Angular ngContainer vs Angular ng Template vs Angular ngContent vs Angular ngTemplateOutlet
Angular ngContainer vs Angular ng Template vs Angular ngContent vs Angular ngTemplateOutlet

In this post you will learn 4 super important directives inside Angular. And I'm talking here about ngContainer, ngTemplate, ngContent, ngTemplateOutlet.

NgTemplate

First of all let's look on the usage of ngTemplate. Let's say that we want to render an article inside a div.

<div class="article" *ngIf="article; else loading">{{ article.title }}</div>

<ng-template #loadingTemplate>
  <div>Loading..</div>
</ng-template>
export class AppComponent {
article = null
}

As you can see our loading div was rendered. If we provide a valid article inside it will be rendered instead.

export class AppComponent {
  article: { title: string } | null = { title: 'Foo' };
}

This is a really nice approach if you want to render a template when your condition is wrong

You can't use ngTemplate on your own. You need either to use default structural directives (ng-for, ng-if, ng-switch) or with your own custom structural directives.

And one more important point is how Angular uses the code that we wrote here.

<ng-template [ngIf]="article" [ngIfElse]="loading">
  <div class="article">{{ article.title }}</div>
</ng-template>

This is how Angular parses our ngTemplate. It creates 2 directives ngIf and ngIfElse with 2 different templates. And this is fully valid Angular code.

But I must remind you that it is not always necessary to use ngTemplate. You can simply use ngIf twice.

<div class="article" *ngIf="article">{{ article.title }}</div>
<div *ngIf="!article">Loading...</div>

NgContainer

Now let's talk about ngContainer. Why do we need it at all? Sometimes we want to pack several directives in a single element.

<div *ngIf="" *ngFor=""></div>

This code won't work. You must create one more container to split structural directives.

But in some cases it won't work for you. It might be that inside CSS you have a specific nesting and additional container breaks your CSS.

This is why instead we can write 2 ng-containers.

<ng-container *ngIf="numbers">
  <ng-container *ngFor="let number of numbers">{{ number }}</ng-container>
</ng-container>
export class AppComponent {
  numbers = [1, 2, 3];
}

Here we used 2 containers but they won't be rendered in DOM at all. This is just special Angular directives to apply structural directives.

So every single time when you want to avoid creating additional container you must use ng-container.

NgContent

Now let's talk about ngContent. And actually we use it only with child components.

// parent component
<app-child>
  <div>{{ article?.title }}</div>
</app-child>
// child component
<ng-content></ng-content>

So here we render app-child inside our parent component and we provided additional markup inside it. This markup that we provided from parent is what will be rendered inside ng-content in child.

This is the correct way to pass markup from parent to child.

ngTemplateOutlet

Now let's talk about ngTemplateOutlet. Why do we need it at all?

<ng-container
  *ngTemplateOutlet="loadingTemplate"
></ng-container>

<ng-template #loadingTemplate>
  <div>Loading..</div>
</ng-template>

As you can see here we provided an ng-template inside ngTemplateOutlet.

This is the exact way to render template without structural directives.

As you can see in browser loading template was successfully rendered.

But sometimes we need to pass some data to the template before rendering. And it is completely possible with context.

<ng-container
  *ngTemplateOutlet="articleTemplate;context: {article}"
></ng-container>

<ng-template #articleTemplate let-article="article">
  <div>{{ article.title }}</div>
</ng-template>

As you can see here we passed the object with article property inside our ngTemplateOutlet. When we define articleTemplate we provide properties with let- prefix. In this case we can render data from outside.

And also if you are interested to learn how animations are working in Angular make sure to check this post also.

📚 Source code of what we've done