0

I have created a directive to show/hide element according to permission. Implementation of directive is somehow like:

 <ng-container *appHasAccess="'user.profile'">
<button>Profile</button>
</ng-container>

Directive code is:

import {
  Directive,
  Input,
  OnDestroy,
  OnInit,
  TemplateRef,
  ViewContainerRef,
} from "@angular/core";
import { PermissionsService } from "@core/services/permissions";
import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";

@Directive({
  selector: "[appHasAccess]",
})
export class HasAccessDirective implements OnInit, OnDestroy {
  @Input() appHasAccess: string;
  stop$ = new Subject();

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

  ngOnInit(): void {
    this.permissionsService
      .checkAuthorization(this.appHasAccess)
      .pipe(takeUntil(this.stop$))
      .subscribe((authorized) => {
        if (authorized) {
          this.viewContainer.createEmbeddedView(this.templateRef);
        } else {
          this.viewContainer.clear();
        }
      });
  }

  ngOnDestroy() {
    this.stop$.next();
  }
}

This works for only page refresh scenario. View is not updated on value change. Can anyone help me on this?

NItesh Shrestha
  • 66
  • 3
  • 12
  • From the look of it `this.permissionsService .checkAuthorization(this.appHasAccess)` only get called in ngOnInit and it's not an hot observable but a function call, that's why it won't emit when value change – Fan Cheung May 05 '20 at 06:40
  • @FanCheung Can you suggest a solution for this? – NItesh Shrestha May 05 '20 at 09:21
  • @FanCheung I have already tried with other lifecycles too. Is there any way we can solve with observables? – NItesh Shrestha May 05 '20 at 09:35
  • You will need to post the code for this.permissionsService .checkAuthorization, we have to see where it triggers the auth status/variable change. – Fan Cheung May 05 '20 at 09:39
  • NOTE: I am storing permissions array to local storage – NItesh Shrestha May 05 '20 at 09:44
  • You need to setup multiplex subject to broadcast in your this.permissionsService when the auth status change. – Fan Cheung May 05 '20 at 09:45
  • My code was unable to track the property change in the storage. I was able to solve the above mentioned issue by adding subject to the storage and listening to it. Thanks for the help. – NItesh Shrestha May 10 '20 at 15:42

1 Answers1

0

If I have understood correctly your problem, you could set the current username in the PermissionService as a Subject. That way the service can emit new values when the curren user changes:

service.ts

export class PermissionsService {
  user = '';
  private currentUser = new Subject<string>();

  public setCurrentUser(user) {
    this.user = user;
    this.currentUser.next(user);
  }

  checkAuthorization(): Observable<boolean> {
    return this.currentUser.pipe(
      map( x => { return x === 'me'; })
    )
  }
}

In the above code the checkAuthorization is an observable to which you can subscribe in your Directive. In fact this code is almost the same you had except that I removed the parameter:

directive.ts

  ngOnInit(): void {
    this.permissionsService.checkAuthorization()
      .pipe(takeUntil(this.stop$))
      .subscribe((authorized) => {
        this.viewContainer.clear();
        if (authorized) {
          this.viewContainer.createEmbeddedView(this.templateRef);
        }
      });
  }

Note that you have to clear the viewContainer always because otherwise it would create a new button every time.

Check this demo I made based on your example: https://stackblitz.com/edit/angular-fevt6t

Kari F.
  • 1,214
  • 10
  • 16