Injecting Context through Structural Directives in Angular

Felipe Gonçalves Marques
TaqtileBR
Published in
3 min readJun 19, 2018
Photo by Daniel von Appen on Unsplash

In my previous post, I show how we can use ng-template with ngTemplateRouterOutlet to separate data fetching logic from presenting the data, without polluting other classes. But, specifically for that example, there was a lot of overhead: the data component did not apply any presentation logic (a loading, a show/hide feature, etc), so we have an unnecessary ng-container.

A simpler result can be obtained using Structural Directive, although it is against the Angular recommendation:

"Structural directives are responsible for HTML layout. They shape or reshape the DOM’s structure, typically by adding, removing, or manipulating elements." Angular Guide

But, I think it brings a nice readable layout and provides the functionality we want without too much overhead. Before presenting the solution, let me explain what are Structural Directives.

Structural Directives

This directives are applied to an HTML tag (which can be native or an Angular Component). Its constructor receives a TemplateRef, consisting of the element it is being applied to, and a ViewContainerRef, that represents the view where the component would be rendered. (Actually, Angular replaces the element with an ng-template and uses it to render the component).

This is why this kind of directive are used mainly for HTML layout. The responsibility of rendering the component is passed to them, so we can use only one of these per tag. Examples of this directives are: *ngFor, *ngIf, etc.

The ViewContainerRef allows you to control what is rendered, and inject a context object. In our case, we will be using the following method:

In other words, we will inject the exactly same context object as before!

The code

So let's take a look in how we can implemente this.

This is the code of the directive. As you can see, it doesn't change much from what we did before:

The difference is that instead of having a ContentChild, we receive the TemplateRef on the constructor. Also, there is no *ngTemplateOutlet. We just call the viewContainerRef method: createEmbeddedView to render the TemplateRef.

In this case, we call it on the ngOnInit, because the presentation does not change, only the context. In ngFor and ngIf, the interaction with the viewContainerRef may happen in different points, since what is rendered depends on what is passed as input to the directive.

To use this directive we must do:

As you can see, we use a syntax similar to the *ngFor. We are basically doing the same variables binding that we did in the last post with ng-template. Actually, it is exactly the same, but Angular allows us to use a sugar syntax. This brings us the last topic of the post.

Structural Directive Microsyntax

Angular allows us to use this very semantic syntax with the directive, because it uses something called Microsyntax. It takes the the string you passed to the directive and transform it in other directives. I think it is more clear if we see some examples. The *ngFor works like this:

For our custom directive, it works like this:

The transformation it does is:

So, for the let statement, it transform in variables binding. For other directives (as of and trackBy), it transforms in Input directives by title-casing the statement and prefixing it with the the directive name. And thats all!

Structural directive are a powerful tool for reusability in Angular and are great for improvement code readability with its Microsyntax.

Hope you gained more understanding of Structural Directives and how to use it as building block for some reusable components. Take a look below to get some links to learn more!

If you want to know more about structural directives, take a look at Angular guide about it.

The guide suggests to take a look at *ngFor source code, but I got confuse trying to understand it together with the IterableDiffer class. So, I think it is better to take a loot at *ngTemplateOutlet source code.

Finally, this article was inspired by this tutorial.

--

--