2016-04-02 7 views
22

私のAngular 2アプリでは、私はお互いに依存する2つのサービスを持っています(サービスAはサービスBの呼び出しメソッド、その逆)。 はここに関連するコードです: app.component.tsで:Angular2:2のサービスはお互いに依存します

import {Component} from 'angular2/core'; 
import {TempService} from '../services/tmp'; 
import {Temp2Service} from '../services/tmp2'; 

@Component({ 
    selector: 'my-app', 
    templateUrl: 'app/app/app.component.html', 
    providers: [TempService, Temp2Service] 
}) 
export class AppComponent { (...) } 

サービス1:

import {Injectable} from 'angular2/core'; 
import {Temp2Service} from './tmp2'; 

@Injectable() 
export class TempService { 
    constructor (private _sessionService: Temp2Service) {} 
} 

サービス2:

import {Injectable} from 'angular2/core'; 
import {TempService} from './tmp'; 

@Injectable() 
export class Temp2Service { 
    constructor (private _sessionService: TempService) {} 
} 

アプリを実行すると、次のエラーにつながります:

EXCEPTION: Cannot resolve all parameters for 'Temp2Service'(undefined). Make sure that all the parameters are decorated with Inject or have valid type annotations and that 'Temp2Service' is decorated with Injectable

サービスのいずれかでコンストラクタにコメントすると、アプリはうまく動作します。 私の推測では、2つのサービスの「相互参照」が問題を引き起こしていると考えられます。 ここで何がうまくいかないのか考えていますか? 私のアプローチはすでに間違っていますか?

お寄せいただきありがとうございます!

+4

角度には、Temp2Serviceを構築するためのTempServiceが必要であり、TempServiceを構築するにはTemp2Serviceが必要です。それは鶏と卵の問題です。 3番目のサービスを作成し、3番目のサービスに委任して依存関係を解除します。 –

答えて

22

これは循環依存と呼ばれます。 Angular2自体の問題ではありません。私が知っている言語では許可されていません。

この循環依存関係を削除するには、コードをリファクタリングする必要があります。おそらく、これらのサービスの1つを新しいサービスに分割する必要があります。

責任ある原則に従えば、循環依存トラップにならないことがわかります。

+37

実際、私が知っているすべての言語で循環依存が許可されています。問題は、依存関係がコンストラクタによって必要とされることです。もしそうでなければ、あなたは 'a = new A(); b = new B(); a.b = b; b.a = a; '。あなたは依然として循環依存関係を持ちますが、すべてが正常に動作します。私は循環依存が良いことだと言っているわけではありません。彼らは可能だと言っているだけです。 –

+1

場合によっては、循環依存を避けることはできません。私はJulian FARHIの答えが有用な前方参照を参照しています。私の問題を解決しました。 –

+3

'forwardRef'は、同じファイル内のクラスの循環依存性のためのものです。私の答えはDIの依存関係です。 'forwardRef'は、注射可能物の循環コンストラクタの依存性に影響を与えません。コンストラクタから一つの依存関係を削除してサイクルを中断し、代わりに 'Injector'を注入し、' setTimeout(()=> {this.someDep = injector.get(SomeDependency);} 'を使用すると回避できます。 –

0

インターフェイスを使用する - これは多くの言語で共通のパターンです。

参照Güntersは、あなたがシングルトンを持っていないことは許容される場合のいずれかのサービスにNEWを呼び出そうとすることができます

Circular dependency with Angular 2 and SystemJS

1

に答えます。 like

これはどちらのサービスも未定義のメンバー変数を使用していないため、私が取ったアプローチでした。

+0

を解決するための具体的なオプションを提供しています。あなたが '@Ijectable'を必要としない場合は - 非常に静的なオブジェクト/クラスの場合 – Cody

6

循環依存性に関するAngular 2のドキュメントの章があります。私は非常に便利だと思います。

Dependency injection

14

コンストラクタの注入は、円形の依存関係を防ぎます。

それはInjectorを注入し、同様に命令的依存関係を要求することにより分割することができます:あなたは角度2を使用して、それぞれの機能を呼び出すための循環依存関係を必要としている場合は

private payrollService:PayrollService; 
constructor(/*private payrollService:PayrollService*/ injector:Injector) { 
    setTimeout(() => this.payrollService = injector.get(PayrollService)); 
} 

Circular dependency injection angular 2

+1

これはハックのように見えます – raneshu

+2

あなたは何を期待しますか?コンストラクタインジェクションは循環依存関係では機能しません。円を取り除くことだけが良いオプションです。 –

+0

'this.payrollService = this.injector.get ( 'PayrollService')'は十分に良いはずです。 'setTimeout ...'が必要なのかどうかわからない – raneshu

1

を参照してください。他のイベントではObservablesを使用し、他のサービスを注入したServiceでそれらを購読することができます。

小さな例: -

@Injectable() 
class Service1{ 

observeEvents(){ 
return Obsevable.create((o)=>{ 
//store `o` it in any class variable 
//whenever you want to call function of Service2 from this class, do this `o.next('method_name');` 
}); 
} 
} 

@Injectable() 
class Service2{ 
    constructor(private service1: Service1){ 
    this.service1.subscribe((method)=>{ 
     this[method](); 
}); 
    } 
} 
+0

これらはすべてハックです(適切なデコレータを提供してくれていないため、Angular2です) - これがハックです。しかし、代替ソリューションへの小道具。 – Cody

+0

@Cody sir、ハッキングは許可されていませんか? –

+0

はい、ハックは許可されています - 私はそう思っていますが、私はこれに関するアービターではありません。私はこれがちょっとのことだと言っていました - Angularがそれほど多くを提供しているわけではありません。私は別の解決策の提案に感謝します - 私はAngularに対するものよりも、あなたに対するポイントはもう数えていませんでした。 – Cody

0

私たちは、この問題を解決するためにforwordRef機能を解決することができます。

//まだ定義されていない参照を参照することができます。

@Inject(forwardRef(()=> MyServiceで))プライベートHTTPPROXY:MyServiceで

2

私はインジェクタのクラスを使用して角度> 4で動作するように、このソリューションを更新し、あなたが他のサービス

import { Injector } from '@angular/core'; 
import { TempService } from './tmp'; 


@Injectable() 
export class Temp2Service { 

    private tempService: any; 

    constructor (private injector: Injector) { } 

    public funcA() { 
    this.tempService = this.injector.get(TempService); 
    this.tempService.doSomething(); 
    } 
} 
にサービスを注入することができます
+0

これはAngular 4.0では役に立ちません。 – Senthe

+0

これは火で遊んでいます - それを避けてください:) –

+0

@AlexanderMills:なぜ火で遊んでいると言いますか?あなたはもっと良い解決策を持っていますか?ありがとうございました。 –

0

これは循環依存であり、残念ながら、それはAngularが解決できない基本的なコンピュータサイエンスの問題または情報の問題です。代わりに次のようにしてください:

export class ServiceA{ 
constructor(private b: ServiceB){ 
    b.setA(this); 
} 
} 

export class ServiceB { 

private a: ServiceA 

constructor(){ 

} 

setA(a){ 
    this.a = a; 
} 

} 

おそらくこれを行う最良の方法です。

関連する問題