Reputation: 1668
How would I go about injecting one service into another? Let's for example say I have a Collection that requires another Collection (TeamCollection => PlayerCollection). Currently I just create two separate Collections and use something like:
import {PlayerCollection} from "<<folder>>/player";
But this requires me to write my own singleton getInstance code within Typescript for each and every service that I want to be a singleton instance.
What is the correct way to do this? I want to have both singletons within my Components and be able to @Inject one service into another using the constructor syntax, without creating a new instance of the singletons.
class TeamCollection {
constructor(@Inject(PlayerCollection): PlayerCollection) {}
}
Upvotes: 27
Views: 27127
Reputation: 9471
What you need to make sure of is the following:
You can only inject the service once you have "provided" the service. When doing this in a @component its easy because you have the providers [ .... ] statement.
When you want to do this for a service you do not have the providers:[].... so the only place you can do this is during bootstrap time where you need to specify the service in
boostrap(app, [
PlayerCollection,
Other,
More Services...
]
If you dig in the documentation it specifically says you need to do it this way.
Upvotes: 1
Reputation: 554
I found that another way of having a singleton service is by creating the singleton pattern with a getInstance() method that calls the constructor, then you don't inject your service to the component constructor, but just reference it as a static class. You can check sample code in here:
Access key data across entire app in Angular 2 & Ionic 2
Look for my answer, I think its the second in the page. If it works for you I would appreciate if you could up-vote it. Thanks.
Upvotes: 1
Reputation: 1668
So after re-reading this excellent post by Pascal Precht: http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular-2.html
And seeing him comment on: http://twofuckingdevelopers.com/2015/04/angular-2-singleton-service/
"Everything injected using Angular 2’s DI is already a Singleton. No need for such a service"
I went testing, and what I now found has both answered my question and made me even more confused about the topic of DI in angular2.
See the following code:
team.ts
import {BaseCollection, BaseModel} from "./base";
import {PlayerCollection} from './player';
import {Injectable, Inject} from "angular2/angular2";
@Injectable()
export class TeamCollection extends BaseCollection {
playerCollection: PlayerCollection;
constructor(@Inject(PlayerCollection) playerCollection: PlayerCollection) {
super();
this.playerCollection = playerCollection;
}
create(data: Object): TeamModel {
return new TeamModel(data);
}
}
player.ts
import {BaseCollection, BaseModel} from "./base";
import {Injectable} from "angular2/angular2";
@Injectable()
export class PlayerCollection extends BaseCollection {
create(data: Object): PlayerModel {
return new PlayerModel(data);
}
}
team.spec.ts
/// <reference path="../../typings.d.ts" />
//VERY IMPORTANT TO ALWAYS LOAD THESE
import 'zone.js';
import 'reflect-metadata';
import 'es6-shim';
import {TeamModel, TeamCollection} from "../../app/model/team";
import {PlayerCollection} from "../../app/model/player";
import {Inject, Injector} from "angular2/angular2";
describe('TeamCollection', () => {
var teamCollection: TeamCollection;
var playerCollection: PlayerCollection;
beforeEach(() => {
var injector = Injector.resolveAndCreate([
TeamCollection,
PlayerCollection
]);
teamCollection = injector.get(TeamCollection);
var injectorT = Injector.resolveAndCreate([
PlayerCollection
]);
playerCollection = injector.get(PlayerCollection);
});
it('should have a singleton PlayerCollection shared between all classes within the application', () => {
console.log(teamCollection.playerCollection.uuId);
console.log(playerCollection.uuId);
});
});
As long as it was the same Injector (var injector
) that created both they share the same uuID Though when I use a second injector (var injectorT
) the UUIDs are different meaning a new instance is created of the playerCollection.
Now my question would be. If I use the component providers syntax:
@Component({
selector: 'app',
providers: [TeamCollection]
})
@Component({
selector: 'player-list',
providers: [PlayerCollection]
})
Would both share the same player collection or would both create a new instance?
Edit:
They do as long as they are created through the bootstrap(.., [ServiceA,ServiceB])
method.
Thanks to pascal precht http://blog.thoughtram.io/angular/2015/09/17/resolve-service-dependencies-in-angular-2.html
Upvotes: 16