5

Consider this Angular 6 component

@Component({
  template: '<div my-directive>content</div>'
})
export class ACustomComponent {}

What is the simplest way for me to inject the specific instance of the component inside the directive's constructor?

@Directive()
export class MyDirective {
  // how to reference the component whose template hosts this directive?
  constructor(private hostComponent: Component) {}
}

The simplest way I've thought to do this is to use a service provided in @Component(), store the component instance in a service property, then inject that same service in the directive and retrieve the instance from that property. Wondering if there is a simpler, more generic way (so I don't have to provide that service every time I need to do this) that means the directive doesn't need to know the type of its host component.

PS: My question is different from this one because whereas the other wants the component instance that the directive is directly applied to -- <my-cmp my-directive></my-cmp>, I'm asking for the nearest parent component whether the directive is applied to it directly or to a native HTML element within its template.

Basically, the problem I want to solve is: I need to execute methods within the directive and bind them to the this context of the component that hosts them without the directive knowing the component's type ahead of time.

someMethod.bind(this.hostComponent)();
BeetleJuice
  • 39,516
  • 19
  • 105
  • 165
  • Have a look at https://github.com/angular/angular/issues/8277#issuecomment-311032673 if it is helping – Yousef khan Aug 07 '18 at 03:31
  • or may be this https://github.com/angular/angular/issues/8277#issuecomment-323678013 – Yousef khan Aug 07 '18 at 03:33
  • @ConnorsFan I don't think so. In that posting, the directive is applied specifically to the component, like ``. That isn't the case here. I am looking for the nearest parent component whether the directive is applied directly to it or within its template. I'll edit the question a bit to make that clearer. – BeetleJuice Aug 07 '18 at 09:57
  • @Yousefkhan thanks for the suggestion. The first requires me to inject a provider every time (my current solution), and the second allows me only to access the host if the directive is directly applied to it, like `` – BeetleJuice Aug 07 '18 at 10:07

1 Answers1

4

For a dynamic component type,I do like this, it works on Angular 9.

export class FromItemComponentBase  {
  constructor(private hostElement: ElementRef) {
    hostElement.nativeElement.__component=this;
  }
}

@Component({
  selector: 'input-error',
  templateUrl: 'component.html'
})
export class FromItemErrorComponent extends FromItemComponentBase {
  constructor(private hostElement: ElementRef) {
    super(hostElement);
  }
}

@Component({
  selector: 'input-password',
  templateUrl: 'component.html'
})
export class FromItemPasswordComponent extends FromItemComponentBase {
  constructor(private hostElement: ElementRef) {
    super(hostElement);
  }
}

@Directive({selector: 'input-error,input-password,input-text'})
export class FormInputDirective {
  component:FromItemComponentBase;

  constructor(private hostElement: ElementRef) {
    this.component=hostElement.nativeElement.__component;
  }
}
shine
  • 610
  • 3
  • 10