Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 "Services" how to @inject one service into another (singletons)?

Tags:

angular

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) {} } 
like image 216
N.Schipper Avatar asked Nov 06 '15 20:11

N.Schipper


People also ask

Can we inject service in another service Angular?

You can inject an Angular service in a component, service, directive etc by specifying the service and its type in a component's constructor. Note that injecting a service through a class constructor is, in general, tree-shakable.

How do you inject a service into a component?

Angular provides the ability for you to inject a service into a component to give that component access to the service. The @Injectable() decorator defines a class as a service in Angular and allows Angular to inject it into a component as a dependency.


2 Answers

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

like image 98
N.Schipper Avatar answered Oct 12 '22 02:10

N.Schipper


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.

like image 29
Will de la Vega Avatar answered Oct 12 '22 00:10

Will de la Vega