Edward
Edward

Reputation: 1126

Getting parent Component via Injector.get() when token can be multiple values

What I'm trying to do:

Plnkr -> http://plnkr.co/edit/Do4qYfDLtarRQQEBphW3?p=preview

In looking at the angular.io documentation, I've found that "Injector" can be used to obtain the parent Component in the constructor

constructor(private el: ElementRef, private hostComponent:Injector){
    el.nativeElement.draggable = 'true';
}

In doing so, I get Injector Object. From what I can tell I am then supposed to use

this.hostComponent.get(INJECTORTOKEN)

The issues I'm having difficulty grasping is that, the examples provided in Angular, make the assumption that you know the type of Component to provide in the token. ie:

this.hostComponent.get(Image);
this.hostComponent.get(Box);

In the pnkr example, I have two components in my template

<div>
   <h2>Hello {{name}}</h2>
   <my-image></my-image> <!-- Uses the "My Directive" -->
   <my-box></my-box> <!-- Uses the "My Directive" -->
</div>

My questions is, in the "mydirective.ts". how can I leverage the "injector.get()" when I don't know if the parent is an "my-image" or 'my-box' component.

in the sample provided, the directive is triggered "ondrag()". view the Console, for log messages.

Any assistance is gratefully appreciated.

Thank you kindly.

Upvotes: 5

Views: 2785

Answers (1)

yurzui
yurzui

Reputation: 214295

I know several ways to do that:

1) Find a parent by its class-interface

You need the provider's class-interface token like:

export abstract class Parent { }

After that you should write an alias provider on Box and Image component

box.ts

providers: [{ provide: Parent, useExisting: forwardRef(() => Box) }]

image.ts

providers: [{ provide: Parent, useExisting: forwardRef(() => Image) }]

then use it in your directive as shown below

myDirective.ts

export class MyDirective {
  constructor(@Optional() private parent: Parent){}

  @HostListener('dragstart',['$event']) ondragstart(event){
    switch(this.parent.constructor) {
     case Box:
      console.log('This is Box');
      break;
     case Image:
      console.log('This is Image');
      break;
    }
  }
}

Here's Plunker

2) Inject all your parents as Optional token

myDirective.ts

export class MyDirective {
  constructor(
    @Optional() private image: Image, 
    @Optional() private box: Box){}

    @HostListener('dragstart',['$event']) ondragstart(event){
      if(this.box) {
        console.log('This is Box');
      }
      if(this.image) {
        console.log('This is Image');
    }
  }
}

Plunker for this case

3) Use Injector like

export class MyDirective {
  constructor(private injector: Injector){}

  @HostListener('dragstart',['$event']) ondragstart(event){
    const boxComp = this.injector.get(Box, 0);
    const imageComp = this.injector.get(Image, 0);

    if(boxComp) {
      console.log('This is Box');
    }
    if(imageComp) {
      console.log('This is Image');
    }
  }
}

Plunker

Upvotes: 5

Related Questions