2

I cannot find a way to bind multiple inputs in my structural directive:

view

   <div *requiredAccessRight requiredA="[EnumA.A]" requiredB="[EnumB.A]">

directive

   @Directive({
        // tslint:disable-next-line: directive-selector
        selector: '[requiredAccessRight]',
    })
          export class RequiredAccessRightDirective implements OnInit {
                @Input() requiredA: EnumA[];
                @Input() requiredB: EnumB[];
...
           }

during ngOnInit() both Inputs() will end up undefined

yBother
  • 648
  • 6
  • 25

1 Answers1

5

The inputs of directive follows naming convention as follows:

Directive input name = directiveSelector + identifier (first character capital)

So in order to create requiredA and requiredB as inputs you need to have requiredAccessRightRequiredA and requiredAccessRightRequiredB.

After creating these inputs while using the directive, you always need to pass one value as directive name value.

e.g. in requiredAccessRight directive you must have requiredAccessRight as input (this is mandatory).

While using the directive, first value will always be without any iedntifier which will be assigned to directive name value. After that by using ; as separator you can pass other custom inputs.

Directive

import { Directive, TemplateRef, ViewContainerRef, Input } from '@angular/core';

@Directive({
  selector: '[requiredAccessRight]'
})
export class DirectiveDirective {

  private _requiredAccessRight: any;
  private _requiredAccessRightRequiredA: any;
  private _requiredAccessRightRequiredB: any;

  @Input() set requiredAccessRight(value: any[]) {
    this._requiredAccessRight = value;
    console.log(this._requiredAccessRight)
  }

  @Input() set requiredAccessRightRequiredA(enumA) {
    this._requiredAccessRightRequiredA = enumA;
    console.log(this._requiredAccessRightRequiredA);
  }

  @Input() set requiredAccessRightRequiredB(enumB) {
    this._requiredAccessRightRequiredB = enumB;
    console.log(this._requiredAccessRightRequiredB);
  }

  constructor(private templateRef: TemplateRef<any>, private vcr: ViewContainerRef) { }
}

Usage in HTML template

As first value is mandatory you can pass your value from component in place of '' or [], I am just using placeholder here.

<button *requiredAccessRight="'';requiredA: [enumA]; requiredB: [enumB]">click</button>
<!-- or -->
<button *requiredAccessRight="[];requiredA: [enumA]; requiredB: [enumB]">click</button>
<!-- or -->
<button *requiredAccessRight="let i;requiredA: [enumA]; requiredB: [enumB]">click</button>
Plochie
  • 3,944
  • 1
  • 17
  • 33
  • okay so I do have to provide any value for this Input 'requiredAccessRight' even though I only need the 2 other inputs? this kind of smells to me.. – yBother Jan 03 '20 at 14:14
  • Yes. Actually thats how internally it works. If you see this structural directive after evaluation it will generate `[requiredAccessRight]=""` which will require some value. – Plochie Jan 03 '20 at 14:16
  • Thanks. Very useful. I was struggling with passing inputs to my custom "if" directive. – nelson6e65 Jun 27 '21 at 23:45
  • @yBother You can actually pass the values directly in the main input `requiredAccessRight`, as an object or an array. For example, using `*requiredAccessRight="{a: [enumA], b: [enumB]}"` in your template and updating a little your `RequiredAccessRightDirective.requiredAccessRight` setter to handle an object instead of an array, – nelson6e65 Jun 28 '21 at 01:06
  • Frankly speaking, i not sure why structural directive support of multiple inputs cannot follow that of the attribute directive.. The former seem complicated than the latter. – Nick Wills Mar 09 '23 at 18:34