A Useful Trick with `ng-container`
Let’s learn the `ng-container` trick for directives.
We'll cover the following
The <ng-container>
directive is very powerful, and we should definitely learn to use it. In this lesson, we’ll learn a useful trick that will be quite handy when we work with structural directives.
The ng-container
This directive is especially useful for us because it adds an element to the HTML template that we can use, but Angular removes it during the render time. In other words, we can use as many ng-container
elements as we want, and it does not influence the number of DOM nodes at all.
Why is this so useful?
The following few examples demonstrate the usefulness of this directive.
<img [src]="user.avatar"">
<article>
<p> {{ user.name }} </p>
<p> {{ user.mailAddress }} </p>
</article>
We’ll start with a simple template for displaying the user’s information. If the user does not exist, we end up with massive errors regarding access to the avatar, name, and email address of the undefined value.
By now, we know that the best way out of this is to use NgIf
to guard against null
values. However, how should we set up the *ngIf
directive? There’s no container element, so we have two options:
- Create a container, like a
<div>
element, that wraps the content, and put a single*ngIf
directive on that element. - Create two
*ngIf
directives, and put them on the<img>
and<article>
elements.
However, both options should be avoided! Why is that?
- We should not add new elements to the DOM just because it’s easier to implement. We should care about the correct DOM structure and its semantic value.
- We should not create many
NgIf
directives for the same value. This directive not the best in terms of performance. Also, if theNgIf
statement handles observable data, the data will be resolved multiple times. - This is why it’s so great to have the ability to add elements into the template without actually pushing it into the DOM.
That’s why it’s so great to have the ability to add elements in the template without actually pushing it into DOM.
Let’s take a look at the correct solution:
<ng-container *ngIf="user">
<img [src]="user.avatar"">
<article>
<p> {{ user.name }} </p>
<p> {{ user.mailAddress }} </p>
</article>
</ng-container>
In the DOM, this is what it will look like if the user exists:
<img src="john.png">
<article>
<p> John </p>
<p> john@email.com </p>
</article>
Meanwhile, nothing happens if the user does not exist! Isn’t that just perfect?
Let’s move to another example.
Let’s assume we have a list of users that we render using the NgFor
directive. However, some of the data is missing and we don’t want to display a user who doesn’t have proper data:
<ul>
<li *ngFor="let user of users">
{{ user.name }}
</li>
</ul>
Using this example, let’s say there are users without names that we don’t want to present in the UI. What should we do? Some users might think that we should just use the NgIf
directive! However, it’s not that easy. That’s because, in Angular, we can’t apply two structural directives to the same element!
So, we can’t do this:
<ul>
<li *ngFor="let user of users" *ngIf="user">
{{ user.name }}
</li>
</ul>
Making a container over {{ user.name }}
doesn’t make sense, either.
In this case, using the ng-container
is very useful.
<ul>
<li *ngFor="let user of users">
<ng-container *ngIf="user">
{{ user.name }}
<ng-container>
</li>
</ul>
As a result, we guard content against possibly null
values but don’t introduce any new elements in the DOM. That’s great!
Get hands-on with 1400+ tech skills courses.