1
votes

I have the following directive

@Directive({
  selector: "[appHasPermission]",
})
export class HasPermissionsDirective implements OnInit, OnDestroy {
  @Input("appHasPermission") uavId: number;
  @Input("fallbackTemplateRef") fallbackTemplateRef: TemplateRef<any>;

  private hasPermissions = false;
  private unsubscribe = new Subject<void>();

  constructor(
    private elementRef: ElementRef,
    private viewContainer: ViewContainerRef,
    private templateRef: TemplateRef<any>,
    private store$: Store<RootStoreState.IAppState>
  ) {}

  ngOnInit() {
    this.store$
      .pipe(takeUntil(this.unsubscribe), select(UserStoreSelectors.hasPermissionsOnUav(), { uavId: this.uavId }))
      .subscribe((hasPermissions) => {
        this.hasPermissions = hasPermissions;
        this.setElementOperation();
      });
  }

  setElementOperation(): void {
    if (this.hasPermissions) {
      this.viewContainer.clear();
      this.viewContainer.createEmbeddedView(this.templateRef);
    } else {
      this.viewContainer.clear();
      if (this.fallbackTemplateRef) {
        this.viewContainer.createEmbeddedView(this.fallbackTemplateRef);
      }
    }
  }

  ngOnDestroy() {
    this.unsubscribe.next();
    this.unsubscribe.complete();
  }
}

Basically, if the user has permission, show the element, else, show a template provided as input.

The problem is, when I want to use it :

  <button
    *appHasPermission="uav.uavId"
    [fallbackTemplateRef]="noPermission"
    mat-menu-item
    (click)="OnReleasePermission.emit(uav)"

I get prompted with

Can't bind to 'fallbackTemplateRef' since it isn't a known property of 'button'

If I use like

  <button
    [appHasPermission]="uav.uavId"
    [fallbackTemplateRef]="noPermission"
    mat-menu-item
    (click)="OnReleasePermission.emit(uav)"

No Provider for TemplateRef, use *

Why so ? in the documentation https://angular.io/guide/attribute-directives#bind-to-a-second-property this should work

1

1 Answers

2
votes

The documentation you're referring to is for attribute directives. Structural directives have different gramar

*:prefix="( :let | :expression ) (';' | ',')? ( :let | :as | :keyExp )*"

you should be looking into keyExp.

keyExp = :key ":"? :expression ("as" :local)? ";"? 

It means that you should pass your second input as follows:

<button
  *appHasPermission="uav.uavId; fallbackTemplateRef: noPermission"
  mat-menu-item
  (click)="OnReleasePermission.emit(uav)"

or expanded form:

<ng-template [appHasPermission]="uav.uavId" [fallbackTemplateRef]="noPermission"> 
  <button mat-menu-item
    (click)="OnReleasePermission.emit(uav)"

See also: