Sabith Pocker
Poetics of Code

Poetics of Code

Custom Structural Directive in Angular for User Roles

Example code for a custom structural directive in angular which acts similar to *ngIf but can be customised to fit your business logic like user roles or permissions or other cases where the same logic is repeated using *ngIf and makes it hard to change the logic later.

This can be adapted to creating structural directives like *appIfUserIsAdmin ,*appIfFocusMode, *appIfFullScreen or other custom logics and keeps those logic out of your templates.

This example can be used just like *ngIf:

<mat-card *appIfUserRoleIs="'role-a'"
  >Contnet that can be seen by Role A</mat-card
>
<mat-card *appIfUserRoleIs="'role-b'"
  >Contnet that can be seen by Role B</mat-card
>
<mat-card *appIfUserRoleIs="'role-c'"
  >Contnet that can be seen by Role C</mat-card
>

GitHub link: github.com/sabithpocker/angular-custum-stru..

Complete Code

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
import { UserService } from './user.service';

@Directive({
  selector: '[appIfUserRoleIs]'
})
export class IfUserRoleIsDirective {
  private hasView = false;
  private currentUserRole: string;
  private showForUserRole: string;
  constructor(
    private userService: UserService,
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef) {
    this.userService.getUserRole().subscribe(role => {
      this.currentUserRole = role;
      this.updateView();
    });
  }

  @Input() set appIfUserRoleIs(role: string) {
    this.showForUserRole = role;
    this.updateView();
  }
  updateView() {
    const canView = this.canView(this.currentUserRole, this.showForUserRole)
    this.hasView = this.renderView(canView, this.hasView)
  }

  canView(currentRole: string, showForUserRole: string): boolean {
    return currentRole === showForUserRole;
  }

  renderView(show: boolean, hasView: boolean) {
    if (show && !hasView) {
      this.viewContainer.createEmbeddedView(this.templateRef);
      hasView = true;
    } else if (!show && hasView) {
      this.viewContainer.clear();
      hasView = false;
    }
    return hasView;
  }
}
 
Share this