3

I have an abstract class and an implementation of it

export abstract class IPrint {
    abstract Print(textInput: string): void;
}

export class FilePrint implements IPrint {
    Print(textInput: string): void {
        console.log("File Print");
    }
}

Then introduce to Angular DI:

  providers:
    [
      { provide: IPrint, useClass: FilePrint }
    ],

I can use it like the following :

  constructor(private _print: IPrint) { }

  ngOnInit(): void {
    console.log(this._print.Print("HI"))
  }

Now I want to have multi implementation of IPrint

export class ScreenPrint implements IPrint {
    Print(textInput: string): void {
        console.log("Screen Print")
    }
}

Then introduce to Angular DI:

  providers:
    [
      { provide: IPrint, useClass: FilePrint },
      { provide: IPrint, useClass: ScreenPrint }
    ],

When I want to use IPrint, angular does not know which implementation must use :

constructor(private _print: IPrint) { }
Mina Mohammadi
  • 285
  • 1
  • 4
  • 14

2 Answers2

1

I had similar problematic and solve it by having an interface and a list of InjectionToken. That's a bit overkill, but that's allow a lot of flexibility and can by apply to other issues.

In a project, we setup a global print service in a shared module and multiple custom implementation provided by each component. And that without having to explicitly inject (so reference) all possible implementation in global service.

Interface and first implementation

export interface IPrint {
    Print(textInput: string): void;
}

export class FilePrint implements IPrint {
    Print(textInput: string): void {
        console.log("File Print");
    }
}

Create list of service implementation with InjectionToken

 // Keep list of token, provider will give a implementation for each of them
 export const PrintServiceTokens: Map<string, InjectionToken<IPrint>> = new Map();
 // Add File service implementation token
 PrintServiceTokens.set('file', new InjectionToken<IPrint>('file'));

Provider File service implementation

   providers: [
      ...
      // First implementation service
      {
         provide: PrintServiceTokens.get('file'),
         useClass: FilePrint
      }
   ]

Other implementation (could be on another module)

export class ScreenPrint implements IPrint {
    Print(textInput: string): void {
        console.log("ScreenPrint");
    }
}

Add token for other implementation

PrintServiceTokens.set('screen', new InjectionToken<IPrint>('screen'));

Add provider

   providers: [
      ...
      // Other implementation service
      {
         provide: PrintServiceTokens.get('screen'),
         useClass: ScreenPrint
      }
   ]

Finally, in a component or service

    myPrintService: IPrint;

    constructor(private injector: Injector) {
       // Up to you to choose service to use, a simple string could be provided by a @Input
       this.myPrintService = this.injector.get(PrintServiceTokens.get('file'));
       this.myPrintService = this.injector.get(PrintServiceTokens.get('screen'));
    }
Camille
  • 2,439
  • 1
  • 14
  • 32
0

angular does not know which implementation must use :

angular knows. Angular will use ScreenPrint. You just override the injection token for IPrint. You can not have different implementations at a time for one injection-token.

enno.void
  • 6,242
  • 4
  • 25
  • 42