Skip to content

Instantly share code, notes, and snippets.

@peplocanto
Last active January 20, 2022 17:32
Show Gist options
  • Save peplocanto/944f77e9840815fd5358ea1a7dda1383 to your computer and use it in GitHub Desktop.
Save peplocanto/944f77e9840815fd5358ea1a7dda1383 to your computer and use it in GitHub Desktop.
Angular custom ngIf directive

Custom ngIf directive

Intro

Setup for a custom ngIf directive.

Arch

 app
 L common
   L directives
     L <name>.directive.ts

First type - without extending Angular ngIf directive

import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
import { Permission } from '@models/user';
import { SessionQuery } from '@store/session/session.query';

@Directive({
  selector: '[hasPermissions]' // IMPORTANT same name as set!
})
export class HasPermissionsDirective {
  @Input() set hasPermissions(permissions: Permission[]) { // IMPORTANT same name as selector!
    const hasUserPermissions = this.sessionQuery.hasUserPermissions(...permissions);
    this.updateView(hasUserPermissions);
  }

  constructor(
    private readonly viewContainer: ViewContainerRef,
    private readonly template: TemplateRef<any>,
    private readonly sessionQuery: SessionQuery
  ) {}

  private updateView(show: boolean): void {
    if (show) {
      this.viewContainer.createEmbeddedView(this.template);
    } else {
      this.viewContainer.clear();
    }
  }
}

Second Type - extending Angular ngIf directive

import { NgIf } from '@angular/common';
import { ChangeDetectorRef, Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';
import { Permission } from '@models/user';
import { SessionQuery } from '@store/session/session.query';

@Directive({
  selector: '[hasPermissions]' // IMPORTANT same name as set!
})
export class HasPermissionsDirective {
  private ngIfDirective: NgIf;

  @Input() set hasPermissions(permissions: Permission[]) { // IMPORTANT same name as selector!
    const hasUserPermissions = this.sessionQuery.hasUserPermissions(...permissions);
    this.updateView(hasUserPermissions);
  }

  constructor(
    private template: TemplateRef<any>,
    private viewContainer: ViewContainerRef,
    private changeDetectorRefs: ChangeDetectorRef,
    private readonly sessionQuery: SessionQuery
  ) {
    if (!this.ngIfDirective) {
      this.ngIfDirective = new NgIf(this.viewContainer, this.template);
    }
  }

  updateView(show: boolean) {
    this.ngIfDirective.ngIf = show;
    this.changeDetectorRefs.detectChanges();
  }
}

Store - More Info

import { Injectable } from '@angular/core';
import { Query } from '@datorama/akita';
import { Permission } from '@models/user';
import { SessionState, SessionStore } from './session.store';

@Injectable(
  { providedIn: 'root' }
)
export class SessionQuery extends Query<SessionState> {
  user$ = this.select((state) => state.user);

  get snapshot(): SessionState {
    return this.getValue();
  }

  constructor(protected readonly store: SessionStore) {
    super(store);
  }

  hasUserPermissions(...requestedPermissions: Permission[]): boolean {
    const userPermissions = this.snapshot.user.permissions;
    return requestedPermission.every((p: Permission) => userPermissions.includes(p));
  }
}

Usage

<div>
  <button *hasPermissions="[Permission.view]">View</button>
  <button *hasPermissions="[Permission.view, Permission.edit]">Edit</button>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment