How to write a custom structural directive to display only authorized sections of a page in Angular

abbasogaji

Abbas Ogaji

Posted on February 5, 2020

How to write a custom structural directive to display only authorized sections of a page in Angular

Imagine a scenario where you have a page or form that should only display certain sections or fields based on a user role or authority in an application. For this, you would probably need conditional statements that would drive your display. Traditional *ngIf directive could be used, but for this use-case, we will write a custom derivate with more features;

So let's go:

For our use-case, a user is provided with an array of viewable sections based on role/level/authority, so that a section of a page will only be displayed if it's included in the array.

const userViewableSections = ["bio-section", "friends-section", "posts-section"]

Enter fullscreen mode Exit fullscreen mode
  • Our custom directive name would be "isAuthorized"
  • we would add an asterisk(*) to our directive name *isAuthorized to make use of Angular's microsyntax
  • Our directive will be written like this;

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

@Directive({ selector: '[isAuthorized]'})
export class IsAuthorizedDirective implements OnInit, OnChanges{
  @Input() isAuthorizedIn : string[]
  @Input() isAuthorized : string
  private hasView = false;

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

  ngOnInit() {
    this.configureView()
  }

  ngOnChanges(){
    this.configureView()
  }

  configureView(){
    const isAuthorized = this.isAuthorizedIn.some(i => i == this.isAuthorized)

    if (isAuthorized && !this.hasView) {
        this.vcr.createEmbeddedView(this.templateRef);
        this.hasView = true;
    } else if (!isAuthorized && this.hasView) {
        this.vcr.clear();
        this.hasView = false;     
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Directive Breakdown:

TemplateRef and ViewContainerRef:

TemplateRef represents an embedded template that can be used to instantiate embedded views, so the HTML snippet that houses our directive becomes a templateRef which is then instantiated by the ViewContainerRef.

Microsyntax

Angular's microsyntax features provides us options to pass parameters with the format below;

*isAuthorized="'bio-section'; in : userViewableSections"

the string 'bio-section' is mapped to @Input() isAuthorized and "...; in : userViewableSections" maps the userViewableSections array to @Input() isAuthorizedIn; the microsytax will resolve the "in" to recognize a @Input() variable with "in" appended to the parent directive @Input in camel case format (i.e isAuthorized + In = @Input() isAuthorizedIn)

Summary

In summary, the directive displays our template if the string passed into @Input() isAuthorized, exists in array passed into @Input() isAuthorizedIn

See Screenshots below;

PAGE :

custom-dir-html-page

COMPONENT HTML
angular-html-ngIf

Check out the complete project on GitHub; Project Link

💖 💪 🙅 🚩
abbasogaji
Abbas Ogaji

Posted on February 5, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related