2015-11-06 169 views
26

如何才能将一项服务注入另一项服务?举个例子说,我有一个需要另一个Collection的集合(TeamCollection => PlayerCollection)。目前,我只是创建两个单独的类别,并使用类似:Angular2“服务”如何将@服务注入另一个服务(单身人士)

import {PlayerCollection} from "<<folder>>/player"; 

但是这需要我写内打字稿我自己单身的getInstance代码为每一个服务,我想成为一个单一实例。

这样做的正确方法是什么?我想在我的组件中拥有两个单例,并且能够使用构造函数语法将@Inject一个服务注入另一个服务,而不创建单例的新实例。

class TeamCollection {  
    constructor(@Inject(PlayerCollection): PlayerCollection) {} 
} 

回答

15

所以重新阅读帕斯卡尔普雷希特这个优秀的帖子后:http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular-2.html

而且看到他发表评论:用角2的DI已经是一个Singleton无需http://twofuckingdevelopers.com/2015/04/angular-2-singleton-service/

“一切注入这样的服务“

我去测试了,我现在发现的两个问题都回答了我的问题,并且让我更加关心angular2中DI的主题。

参见以下代码:

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); 
    }); 
}); 

只要它是相同的注射器(var injector)创建它们都共享相同的uuID虽然当我使用第二个注入器(var injectorT)UUID不同意味着一个新的实例被创建的playerCollection。

现在我的问题是。如果我使用组件提供程序的语法:

@Component({ 
    selector: 'app', 
    providers: [TeamCollection] 
}) 

@Component({ 
    selector: 'player-list', 
    providers: [PlayerCollection] 
}) 

这两个都会共享相同的播放器集合还是会创建一个新实例?

编辑: 只要它们是通过bootstrap(.., [ServiceA,ServiceB])方法创建的,

感谢帕普雷希特http://blog.thoughtram.io/angular/2015/09/17/resolve-service-dependencies-in-angular-2.html

+0

所以..任何想法如何使用服务内的其他服务一旦你已经使用Http创建元数据?我尝试了他在底部链接中的示例,但我不明白这是如何将服务注入到其他服务中,或者如何使用它。令人困惑的东西。 – Chrillewoodz

+0

@Chrillewoodz如果你的意思是你应该如何在将其添加到引导方法后将一项服务注入另一项服务。如果你使用Typescript,这很简单。你只是把它放在构造函数中,例如:''构造函数(private http:Http){}“ –

+0

我试过了,但服务总是成为一个空对象,尽管注入的服务包含大量函数。 。我也觉得必须有一种更清洁的方式来将服务注入另一种服务,而不是自举方法。引导方法会变得很混乱,这看起来很奇怪。 – Chrillewoodz

1

我发现,具有单服务的另一种方式是通过调用构造函数getInstance()方法创建单件模式,那你就没有注入您服务组件构造函数,但只是将其作为静态类引用。你可以这里查看示例代码:

Access key data across entire app in Angular 2 & Ionic 2

查找我的回答,我认为它的第二个页面。如果它适合你,我将不胜感激,如果你可以投票。谢谢。

+3

这是一个反模式: -/ –

+0

我会反对使用标准单例模式的建议(至少当我们谈论角服务时)如果您决定构建一个服务,您可以在角度以外的其他项目中使用,您可以当然也要沿着这条路线走下去。 –

1

你需要确保的是以下几点:

一旦你“中规定的”服务只能注入服务。在@component中执行此操作时很容易,因为您拥有提供程序[....]语句。

当你想为一个服务做到这一点,你没有提供者:[] ... ...这样你就可以做到这一点的唯一地方是在引导时,你需要指定

boostrap(app, [ 

PlayerCollection, 
Other, 
More Services... 



] 
服务

如果你在文档中挖掘它明确说你需要这样做。

+3

我发现你的建议没有正确解决这个问题。你能专门指向文档并提供一个搜索字符串来查询页面吗? –