8

I'm learning Angular2 with Typescript and I have a problem.

I have two classe that imprements same interface. How can I inject them to a service as a list ?

I read about opaquetoken https://angular.io/docs/ts/latest/guide/dependency-injection.html#opaquetoken

But I don't know if I need to use it and how to use it.

export interface CheckerInterface {
    check(text : string) : boolean
}

export class Checker1 implements CheckerInterface {
    check(text : string) : boolean {
    //do something 
    return true;
}

export class Checker2 implements CheckerInterface {
    check(text : string) : boolean {
    //do something 
    return true;
}

@Injectable()
export class Service {

  constructor(private checkers: CheckerInterface[]) {  //??
      checkers.foreach( checker => checker.check(somestring));
  }

}

Thanks for any help !

Rafałek
  • 121
  • 2
  • 8

1 Answers1

5

You need to either add the array as a provider, or use multi: true in the provider configuration.

export const CHECKERS = new OpaqueToken('one');

@NgModule({
  providers: [
     { provide: CHECKERS, useValue: [new Checker1(), new Checker2()] },
  ]
})

Or

@NgModule({
  providers: [
     { provide: CHECKERS, useClass: Checker1, multi: true },
     { provide: CHECKERS, useClass: Checker2, multi: true },
  ]
})

The second one is probably preferable, as you let Angular create them, allowing them to be injected with their own dependencies if needed.

Then you just need to use the CHECKERS token when you inject

import { Inject } from '@angular/core';
import { CHECKERS } from './wherever';

constructor(@Inject(CHECKERS) private checkers: CheckerInterface[]) { 

UPDATE

As of Angular 4, InjectionToken is used instead of OpaqueToken

export const CHECKERS = new InjectionToken<CheckerInterface>('CheckerInterface');
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • This is clear and easy for me but... This might me stupid question... I got my providers in app.module.ts and I added this two lines to my other providers . I also added const CHECKERS = new OpaqueToken('checkers'); line. But constructor(@Inject(CHECKERS) [...] is in another file and it 'Cannot find name CHECKERS'. I'm just at begginer level ;| – Rafałek Mar 27 '17 at 15:42
  • You need to export it, then import it. I updated my answer – Paul Samsotha Mar 27 '17 at 15:45
  • Well... I learned a lot today. Thanks! But I wonder if I did something wrong because i get Error: Can't resolve all parameters for Service: (?). – Rafałek Mar 27 '17 at 16:08
  • 1
    This answer helped me solved my problem when combined with the answer from @Günter Zöchbauer at [Inject all Services that implement some Interface](https://stackoverflow.com/questions/35916542/inject-all-services-that-implement-some-interface/35916788#35916788). This answer needs to change the deprecated OpaqueToken with the new [InjectionToken](https://angular.io/api/core/InjectionToken). – MartinJH Sep 04 '18 at 07:40