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.
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) {}
}
maybe rethink your design
I think you might have to rethink your design altogether then. What's the point of having two variables that point to the exact same EditorService? If they share the same implementation.
Inheritance solution
A solution to this would perhaps be to use Inheritance. I have not seen your services so I am not sure what they do, but from this code I am assuming that the "apple" functionality and the "pear" functionality is actually different. Then this is indicating you might have some design issues, and your EditorService might be doing too much. Perhaps you could move the code that is similar for both Apples and Pears to a service called EditorService
and then have two classes extend this. an AppleEditorService
and a PearEditorService
.
Use general fruitService
Just to talk a bit more about why I think you might need to rethink your design. Let's assume that appels and pears actually do have the same functionality. So the EditorService
does the same. You want one variable to be used for 'Apples' and one for 'Pears'. If I see that code (assume other people work on your team), and I notice that both variables point to the same service. (Services are singletons), I would just be tempted to remove that and make something like fruitService : EditorService
or something of the likes.
Either way your question makes me think the design should be changed. You don't want two instances of the service, services are singleton and although you could find ways around it, I don't think that's really the solution to your problem.
But as I have mentioned before. Think about your design. Do you really need two child-services, or can you solve it differently? Can you have apples and pears just subclass fruit? Can you just use one variable 'fruitService' instead of both apples/pears? What happens when you want to store "Strawberries" as well in the future? Having a bunch of variables refer to the same service (because they do the same thing) but with different variable names is not a good idea. Imagine seeing this in code
appleService = EditorService;
pearService = EditorService;
starwberryService = EditorService;
lemonService = EditorService;
...
guavaService = EditorService;
Would this not indicate something is weird with the code? I can imagine (you didn't provide the code at this point) that you store an Array of the fruitInstances. But then maybe a fruitService could work and then store fruitService.store(Apple a) and put that in an array of 'fruit'. Use a 'filter' to get the right fruit from the array shouldn't be too hard.
^ This is just written without having more of your code to go on. If you edit your question, some things might not hold up anymore.
Not ideal, but if you create a module to each component, and then import your service on each module, you'll have 2 instances of the same service (one for each module).