Using multiple instances of the same service

DavidDuwaer picture DavidDuwaer · Jul 20, 2016 · Viewed 24.2k times · Source

I have a service, like this:

@Injectable()
export class EditorService { ... }

And I have a component, like this:

@Component({
    ...
    template: `<child-component></child-component>`,
    providers: [EditorService],
    ...
})
export class SomeComponent {
    constructor(
        private _appleEditorService: EditorService,
        private _pearEditorService: EditorService) {}
}

As you may have noticed, this component has a child component:

@Component({
    ...
    selector: 'child-component',
    ...
})
export class ChildComponent {
    constructor(
        private _appleEditorService: EditorService,
        private _pearEditorService: EditorService) {}
}

As you can see, I want two instances of my EditorService: one will be used for editing apples and one for editing pears. However, the code above is not going to work, since there is no way for Angular to know which instance of EditorService is which as their variable names are private. _pearEditorService in ChildComponent might as well be referring to the same instance as _appleEditorService in SomeComponent.

Question: How else then, can I use the same Angular2 service twice?

EDIT: The point of my question is if it is possible using the same class. I know there are workarounds by actually creating a seperate class for every instance of the service, and even doing that with little code by inheritance. I just want to know if it can be done without.

Answer

G&#252;nter Z&#246;chbauer picture Günter Zöchbauer · Jul 20, 2016

Angular DI maintains a single instance per provider. In your case if you have two constructor parameters with the same type, they resolve to the same instance.

What you can do is to provide a factory function (different from a simple useFactory provider event though it uses it as well)

(Example copied from https://stackoverflow.com/a/37517575/217408)

{ provide: EditorService, useFactory: 
    (dep1, dep2) => {
        return (x) => { 
            new EditorService(x, dep1, dep2);
        }
    }, deps: [Dep1, Dep2]
})

....

constructor(@Inject(EditorService) editorServiceFactory: any) {
  let editorService1 = editorServiceFactory(1);
  let editorService2 = editorServiceFactory(2);
}

If you have a fixed number of instances this should work:

{ provide: 'instance1', useClass: EditorService },
{ provide: 'instance2', useClass: EditorService },
export class SomeComponent {
    constructor(
        @Inject('instance1') private _appleEditorService: EditorService,
        @Inject('instance2') private _pearEditorService: EditorService) {}
}