Angular Custom Structual Directive

Structural directives looks like normal HTML attribute but with a leading star. they affect the whole area in the DOM, it means they change the structure of the DOM around the element they added on. for example, *ngIf can remove an element from the DOM. 

The leading star indicates to angular that this is a structural directive, beyond the scenes angular will transform them into something else, to an ng-template with a [ngIf] without a star. so the code below:


<div *ngIf="isShowing"> 
  <p>some text</p>
</div>

will transform to:


<ng-template [ngIf]="isShowing" >
  <div> 
    <p>some text</p>
  </div>
</ng-content>

We will crete a simple structual directive that is the opposite of ng-if. we will show the element only when we pass a false value to the directve.

For that we will create a property and attach to it an @Input decorator. this property will be a setter method since we want to be able whenever the value we pass to the directive is changing to run some logic. when the value is false, we will add the element to the DOM and when the value turn true we will remove it from the DOM.

Keep in mind 2 things:

  • Setter is a method that executed whenever the property is changes, but technically this is still a property.
  • the name of the property need to have the same name as the directive

Now we need to display the element or remove it, we know that in the end the elemen will sit in ng-template so we will inject TemplateRef.

We need also to get access to the place in the document where we want to render it and for that we will inject the ViewContainerRef.

below is the final code


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

@Directive({
  selector: "[appStructual]"
})
export class StructualDirective {
  @Input() set appStructual(condition: boolean) {
    if (!condition) {
      this.vcRef.createEmbeddedView(this.templateRef);
    } else {
      this.vcRef.clear();
    }
  }

  constructor(
    private templateRef: TemplateRef,
    private vcRef: ViewContainerRef
  ) {}
}


<div *appStructual="false">
  <p>structual directive example</p>
</div>

Click here for live demo