В этой статье показано, как использовать структурные директивы в Angular для предоставления простого декларативного механизма условного отображения контента.

Предположим, у нас есть проект с ролями «АДМИН», «РАЗРАБОТЧИК», «ПОЛЬЗОВАТЕЛЬ», и мы хотим скрыть части представления для определенных ролей.

Изначально нам нужно было

  1. В каждом представлении добавьте директивы *ngIf с проверкой роли пользователя
  2. Внедрить сервис в компонент, чтобы предоставить роль пользователя
  3. Предоставление компонента общедоступной собственности для отображения роли

Но это скучная копипаста… мы можем сделать это более причудливым способом, используя структурные директивы:

<div *visibleFor="['ADMIN', 'DEV']">
Visible for admin and dev
</div>
<div *visibleFor="'USER'">
Visible for user
</div>

Гораздо проще читать и декларативнее, верно? Итак, давайте реализуем директиву visibleFor

@Directive({
   selector: '[visibleFor]'
})
export class VisibleForDirective implements OnDestroy, OnInit {
   private hasView: boolean = false;

   private user$: Observable<User>;
   private subscription: Subscription = new Subscription();

   @Input() public set visibleFor(inputRoles: RoleString | Array<RoleString>) {
      const roles = isArray(inputRoles) ? inputRoles : [inputRoles];
      this.subscription.unsubscribe();
      this.subscription = this.user$.pipe(untilDestroyed(this))
         .subscribe((user?: User) => {
           const hasAccess = user ? includes(roles, user.role) :    false;
         if (hasAccess && !this.hasView) {
            this.viewContainer.createEmbeddedView(this.templateRef);
            this.hasView = true;
         } else if (!hasAccess && this.hasView) {
            this.viewContainer.clear();
            this.hasView = false;
         }
         this.changeDetector.markForCheck();
      });
   }

   constructor(
      private templateRef: TemplateRef<any>,
      private viewContainer: ViewContainerRef,
      private changeDetector: ChangeDetectorRef,
      private userService: UserService) {}
   public ngOnInit(): void {
     this.user$ = this.userService.getUserRoles();
   }
   public ngOnDestroy(): void {}
}

Сам код говорит сам за себя. Он принимает оба массива строки. Он также использует сеттер для @Input(), поэтому каждый раз, когда ввод изменяется, вызывается весь сеттер.

Здесь используется замечательный оператор untilDestroyed https://github.com/NetanelBasal/ngx-take-until-destroy.

UserService — ваш поставщик данных, а RoleString — ваша строка для определения ролей пользователей:

type RoleString = ‘ADMIN’ | ‘DEV’ | ‘USER’;

Если вы хотите видеть больше похожего контента, пожалуйста, дайте мне знать, похлопав в ладоши.