Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom *ngIf with an else template but no conditional @Input()

So I have a custom ngIf directive that I'm using to handle user authorization, but now I want to make one for certain roles so that I don't have to keep providing them.

Essentially I want to turn this:

<div *appHasAnyRole="['EDIT_USER']; else viewUserTemplateRef">

into something like this:

<div *appIsEditUser="else viewUserTemplateRef">

However, since the directive already knows what role it's looking for, I don't need to provide it a conditional input, so I can't do this in the usual way of:

@Directive({
  selector: '[appHasAnyRole]'
})
export class HasAnyRoleDirective {

  @Input()
  appHasAnyRole(roles: string[]) { ... }

  @Input()
  appHasAnyRoleElse(templateRef: TemplateRef<NgIfContext> | null) { ... }

}

But, trying something like this also isn't working either.

<div *isEditUser [else]="viewUserTemplateRef">
@Directive({
  selector: '[appIsEditUser]'
})
export class IsEditUserDirective {
 
  @Input()
  else(templateRef: TemplateRef<NgIfContext> | null) { ... }

}

It throws the 'ol "Can't bind to 'appElse' since it isn't a known property of 'div'." error at runtime.

The closest I've been able to do was leave both inputs as is, and just ignore the conditional input in the directive code, so it looks something like this in the template:

<div appIsEditUser="''; else viewUserTemplateRef">

I'd prefer not to have to do that. Is there another way I'm missing to bind to fields of a directive without using the "default" (named after directive) @Input() ??

like image 380
LoganBlack Avatar asked Sep 18 '25 02:09

LoganBlack


1 Answers

You need to wrap it around ng-tempalte, so input works

<ng-template appIsEditUser [else]="viewUserTemplateRef">

@Directive({
  selector: '[appIsEditUser]',
})
export class IsEditUserDirective {
  @Input()
  else(templateRef: TemplateRef<NgIfContext> | null) {
    // handle you else here
    console.log(templateRef);
  }
}

or remove role property completely

<div *appIsEditUser="viewUserTemplateRef"></div>
<ng-template #viewUserTemplateRef >It will be rendered as fallback</ng-template>

@Directive({
  selector: '[appIsEditUser]',
})
export class IsEditUserDirective {
  @Input()
  appIsEditUser(templateRef: TemplateRef<NgIfContext> | null) {
    // handle you else here
    console.log(templateRef);
  }
}

I found a way to do it following https://angular.io/guide/structural-directives#shorthand-examples Here is a stackblitz https://stackblitz.com/edit/angular-empty-project-zfbnfg?file=app/app.component.html

Basically, you need to create an empty context variable for that, so the syntax is valid. You can populate it with any useful value you want.

<div *appIsEditUser="let context else viewUserTemplateRef"></div>
<ng-template #viewUserTemplateRef>It will be rendered as fallback</ng-template>

@Directive({
  selector: '[appIsEditUser]',
})
export class IsEditUserDirective {
  @Input()
  appIsEditUserElse(templateRef: TemplateRef<NgIfContext> | null) {
    // handle you else here
    console.log(templateRef);
  }
}
like image 127
Steve Avatar answered Sep 19 '25 18:09

Steve