1

Recently our project is upgraded from Angular 8 to Angular 12, since then I am unable to access the host component reference in the directive

Below is my directive in Angular 8

export class CardNumberMaskingDirective implements OnInit {

  unmaskedValue: string;

  constructor(private control: NgControl,
              private element: ElementRef,
              private _viewContainerRef: ViewContainerRef) {}

  ngOnInit() {
    this.hide(this.element.nativeElement);
  }

  @HostListener('focusout', ['$event.target'])
  hide(input) {
    const host = this._viewContainerRef['_view'].component;
    if (host['disableMask'] instanceof Function) {
      host['disableMask'](this.control.name);
      setTimeout(() => {
        this.unmaskedValue = input.value;
        const value = input.value.replace(/\s/g, '');
        if (value.length > MASKED_LENGTH) {
          const formatted = input.value.replace(MASKING_REGEXP, '●●●● ●●●● ●●●● ');
          this.control.valueAccessor.writeValue(formatted);
        }
      }, 0);
    }
  }

  @HostListener('focusin', ['$event.target'])
  show(input) {
    const host = this._viewContainerRef['_view'].component;
    const value = input.value.replace(/\s/g, '');
    if (value.length > MASKED_LENGTH) {
      this.control.valueAccessor.writeValue(this.unmaskedValue);
    }
    if (host['enableMask'] instanceof Function) {
      host['enableMask'](this.control.name);
    }
  }

}

In Angular V12 we don't have _view and I have to use _hostLView to access the component reference. But still I don't get component reference in case I use this._viewContainerRef['_hostLView '].component;

I found a similar one here but the solution posted here https://stackoverflow.com/a/69706978 is not working for me (I was not getting the component references) Any suggestions are much appreciated

  • `_` means they are internal variables not meant for public use, so it's unsurprising that you're code has broken. Aside from the hackiness it's hard to see what you are trying to achieve but I would suggest reviewing the approach and probably rewriting it. – wlf Feb 14 '22 at 02:40
  • I am trying to access the host component in the directive. If you see my previous approach in V8, I am using _view and getting the component reference and reading the disableMask function written in host component. – Pruthvi Kanduri Feb 14 '22 at 04:04
  • Try using a package like https://www.npmjs.com/package/ngx-mask – wlf Feb 15 '22 at 07:18

2 Answers2

2

The is no universal way, another option is to use common InjectionToken:

export interface IComponent {}

export const token: InjectionToken<IComponent> = new InjectionToken<IComponent>('IComponent');

@Component({
providers: [{provide: token, useExisting: forwardRef(() => MyComponent1)}]
})
export class MyComponent1 implements IComponent {}

@Component({
providers: [{provide: token, useExisting: forwardRef(() => MyComponent2)}]
})
export class MyComponent2 implements IComponent {}

@Directive({})
export class MyDirective {
    constructor(@Inject(token) component: IComponent){}
}

You can use @Host() or/and @Self() to make it more strict.

kemsky
  • 14,727
  • 3
  • 32
  • 51
0

You can access your host component in a directive by DI.

Example:

constructor(
 @Self() private readonly component: YourComponent
) {}