A Useful Trick with `ng-container`

Let’s learn the `ng-container` trick for directives.

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?

  1. 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.
  2. We should not create many NgIf directives for the same value. This directive not the best in terms of performance. Also, if the NgIf statement handles observable data, the data will be resolved multiple times.
  3. 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 1200+ tech skills courses.