サービスをコンポーネントに挿入する方法はわかっていますが (@Component 経由)、DI を使用してコンポーネントの外部にサービスを渡すにはどうすればよいですか?
言い換えれば、私はこれをしたくないのです:
export class MyFirstSvc {
}
export class MySecondSvc {
constructor() {
this.helpfulService = new MyFirstSvc();
}
}
export class MyThirdSvc {
constructor() {
this.helpfulService = new MyFirstSvc();
}
}
ベストアンサー1
はい、まず最初に、@Injectable
注入したい各サービスにデコレータを追加します。実際、Injectable
名前は少しわかりにくいです。クラスが「注入可能」になるという意味ではなく、コンストラクタ パラメータを注入できるようにデコレートするという意味です。詳細については、この github の問題を参照してください。Angular 4.0 の新機能。
インジェクション メカニズムについての私の理解は次のとおりです。@Injectable
クラスのデコレータを設定すると、Angular は現在の実行チェーンのインジェクタ内の対応するタイプのインスタンスを作成または取得しようとします。実際、Angular2 アプリケーションには 1 つのインジェクタだけではなく、インジェクタのツリーがあります。インジェクタは、アプリケーション全体とコンポーネントに暗黙的に関連付けられています。このレベルの重要な機能の 1 つは、インジェクタが階層的にリンクされていることです。このインジェクタのツリーは、コンポーネントのツリーをマップします。「サービス」にはインジェクタは定義されていません。
サンプルを見てみましょう。次のようなアプリケーションがあります。
コンポーネント:関数
AppComponent
内でAngular2アプリケーションを作成するときに提供されるアプリケーションのメインコンポーネントbootstrap
@Component({ selector: 'my-app', template: ` <child></child> `, (...) directives: [ ChildComponent ] }) export class AppComponent { }
コンポーネント:コンポーネント
ChildComponent
内で使用されるサブコンポーネントAppComponent
@Component({ selector: 'child', template: ` {{data | json}}<br/> <a href="#" (click)="getData()">Get data</a> `, (...) }) export class ChildComponent { constructor(service1:Service1) { this.service1 = service1; } getData() { this.data = this.service1.getData(); return false; } }
2つのサービス、
Service1
およびService2
:は、およびによってService1
使用されますChildComponent
Service2
Service1
@Injectable() export class Service1 { constructor(service2:Service2) { this.service2 = service2; } getData() { return this.service2.getData(); } }
@Injectable() export class Service2 { getData() { return [ { message: 'message1' }, { message: 'message2' } ]; } }
これらすべての要素とその関係の概要は次のとおりです。
Application
|
AppComponent
|
ChildComponent
getData() --- Service1 --- Service2
このようなアプリケーションでは、3 つのインジェクターがあります。
bootstrap
関数の2番目のパラメータを使用して設定できるアプリケーションインジェクタAppComponent
このコンポーネントの属性を使用して構成できるインジェクター。providers
アプリケーション インジェクターで定義された要素を「参照」できます。つまり、このプロバイダーでプロバイダーが見つからない場合は、この親インジェクターで自動的に検索されます。後者で見つからない場合は、「プロバイダーが見つかりません」というエラーがスローされます。ChildComponent
1と同じルールに従うインジェクター。AppComponent
コンポーネントに対して実行されるインジェクション チェーンに含まれる要素をインジェクトするには、最初にこのインジェクターでプロバイダーが検索され、次に 1 でAppComponent
、最後にアプリケーション 1 でプロバイダーが検索されます。
つまり、 をコンストラクターService1
に挿入しようとするとChildComponent
、Angular2 はインジェクターを調べChildComponent
、次に を調べAppComponent
、最後にアプリケーションを調べます。
Service2
を に注入する必要があるため、インジェクタ1 とアプリケーション 1 というService1
同じ解決処理が実行されます。ChildComponent
AppComponent
つまり、コンポーネントの 属性とアプリケーション インジェクターの関数の2 番目のパラメータを使用して、必要に応じて各レベルでService1
との両方を指定できます。Service2
providers
bootstrap
これにより、要素セットの依存関係のインスタンスを共有できるようになります。
- アプリケーション レベルでプロバイダーを定義すると、対応する作成されたインスタンスがアプリケーション全体 (すべてのコンポーネント、すべてのサービスなど) で共有されます。
- コンポーネント レベルでプロバイダーを定義すると、インスタンスはコンポーネント自体、そのサブコンポーネント、および依存関係チェーンに関係するすべての「サービス」によって共有されます。
非常に強力で、必要に応じて自由に整理できます。
対応する plunkr はこちらなので、試してみてください:https://plnkr.co/edit/PsySVcX6OKtD3A9TuAEw?p=preview。
Angular2 ドキュメントのこのリンクが役に立つかもしれません:https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html。
お役に立てれば幸いです(長い回答で申し訳ありません)。Thierry