Angular structural directives demystified #tutorial

This blog is part of an Angular instructional / tutorial series, please find the second edition here: Optimise your Angular app using trackBy.

Angular structural directives demystified

As Angular developers, we use structural directives like ngIf and ngFor all the time. But how do structural directives actually work?

Structural directives are responsible for adding, removing, or manipulating certain parts of the DOM. In a video I recently uploaded to Youtube, I demonstrate how you can build your own Angular structural directive.

Imagine you want to create your own directive ngRepeat, which should repeat a piece of Angular template a number of times.

I know that “ng” is an Angular prefix that you should not use, but I want to emphasize that Angulars own structural directives work the same way.

Let’s look at the template syntax first:

<p *ngRepeat>Repeat me</p>

Note the asterisk. This is just syntactic sugar for the following regular template syntax:

<ng-template ngRepeat>
  <p>Repeat me</p>
</ng-template>

You will notice that nothing is rendered by default. That is because an ng-template should be rendered explicitly.

As follows

First, you have to get the TemplateRef injected, which is the reference to the template element. You also need a ViewContainerRef. You can see it as a reference to the place where the directive is located in the view. In your directive, you can use the createEmbeddedView() method to render your TemplateRef.

And there it is!

import { Directive, OnChanges, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[ngRepeat]'
})
export class RepeatDirective implements OnChanges {
  constructor(private templateRef: TemplateRef<any>,
              private viewRef: ViewContainerRef) { }

  ngOnChanges(): void {
    // clear the view first
    this.viewRef.clear();
    
    // render the template two times (for example)
    this.viewRef.createEmbeddedView(this.templateRef);
    this.viewRef.createEmbeddedView(this.templateRef);
  }
}

And there is so much more you can do.

  • Passing a template context (like an index)
  • Adding input bindings to configure your directive
  • Take advantage of Angulars so-called micro-syntax
  • Implicit template input variables

If you want to know more, look me up on Github or mail dirk@craftsmen.nl Or watch the video and extended code below:

Leave a Reply

Your email address will not be published. Required fields are marked *