Skip to main content

Angular - Custom Structural Directives

Angular concept AKA ngIf

Updated 3 min readMarkdown
Part of seriesWhat I've learned today

I've sometimes asked myself what are *ngIf and *ngFor in Angular but never dig into it before until I faced a case where none of the knowledge I had about Angular concept at that time (services, validators, guards, interceptors, directives) would give me the answer I needed.

What I wanted to do, was an *ngIf like element that I could call in my component to manage my user permissions, something that I would call: *ifHasPermission

It's by searching for more details about *ngIf that I discovered: Structural Directives

What is this?

Structural Directives are the handyman that change the structure of the DOM by adding or removing elements from it.

They are prefixed with * and if you're using Angular I'm sure you know some of them: *ngIf, *ngFor are the most well known.

How to make one?

Let's create our *ifHasPermission structural directive.

I want to be able to use this structural directive like so:

<button *ifHasPermission="user.features.includes('PROFILE')"></button>

For each element of my view to be displayed only if the user feature array contains the required element.

Let's begin with the empty shell of a classic directive :

import { Directive, Input } from "@angular/core";

@Directive({
  selector: "[ifHasPermission]",
})
export class IfHasPermissionDirective {

  constructor() {}

  @Input() set ifHasPermission(condition: boolean) {}
}

Here nothing complexe a simple @Directive decorator with a selector param defining the name of your directive (don't forget the [ ] ).

Then a class IfHasPermissionDirective contains an empty constructor and a ifHasPermission function.

If you're not familiar with the @Input set syntax you can undestand it like so:

  • @Input : Parent to child data transmission, in our case it means that the component we will use the ifHasPermission on will pass some data to our IfHasPermissionDirective

  • set : on change, the property will be equal to the new value

Now let's add the magic :

import { Directive, Input, TemplateRef, ViewContainerRef } from "@angular/core";

@Directive({
  selector: "[ifHasPermission]",
})
export class IfHasPermissionDirective {

  constructor(
    private readonly templateRef: TemplateRef<any>,
    private readonly viewContainer: ViewContainerRef
  ) {}

  @Input() set ifHasPermission(condition: boolean) {
    condition
      ? this.viewContainer.createEmbeddedView(this.templateRef)
      : this.viewContainer.clear();
  }
}

Let's break down this code:

In the constructor we inject two private elements in readonly.

  • TemplateRef: represents an embedded template that can be used to instantiate embedded views.

  • ViewContainerRef: represents a container where one or more views can be attached to a component.

馃挕
I will talk more about those two classes in another article that I will like to this one, I still have some work to do before explaining them to you in simple words.

Now in ifHasPermission() we use a ternary to say:

if(I have the permission){
    "Display the element"
}else{
    "Don't display the element"
}
馃挕
Don't forget to add your directive in your module to be able to use it

And TADAM! You now have a structural directive that you can use in all your application to conditionally display or hide the element of your page.

No comments yet. Be the first to comment.

What I've learned today

Part 3 of 5

This serie gather all the new things I learn on a day to day basis that can be usefull for everyone. It can be about anything, tech, books, people, hack, etc.

Up nextDeno Mysql - Query VS ExecuteWhat's the difference between them?