Angular 2コンポーネントディレクティブがあり、コンポーネントが使用する注入された依存関係が@Input()によって決定されるようにしたいとします。
<trendy-directive use="'serviceA'">
のようなものを記述して、TrendyDirectiveのインスタンスにserviceAを使用させるか、またはserviceBを使用するように指定します。 (これは私が実際にやろうとしていることの単純化されたバージョンです)
(これが最初からひどいアイデアだと思うなら、私はそのフィードバックを受け入れますが、その理由を説明してください。)
ここに私が考えていることを達成する方法の一例を示します。この例では、ServiceAとServiceBが両方とも「superCoolFunction」を持つことでiServiceを実装するインジェクタブルであると想像してください。
@Component({
selector: 'trendy-directive',
...
})
export class TrendyDirective implements OnInit {
constructor(
private serviceA: ServiceA,
private serviceB: ServiceB){}
private service: iService;
@Input() use: string;
ngOnInit() {
switch (this.use){
case: 'serviceA': this.service = this.serviceA; break;
case: 'serviceB': this.service = this.serviceB; break;
default: throw "There's no such thing as a " + this.use + '!';
}
this.service.superCoolFunction();
}
}
これは技術的にはうまくいくと思いますが、動的な依存性注入を行うより良い方法がなければなりません。
それは
// can be a service also for overriding and testing
export const trendyServiceMap = {
serviceA: ServiceA,
serviceB: ServiceB
}
constructor(private injector: Injector) {}
...
ngOnInit() {
if (trendyServiceMap.hasOwnProperty(this.use)) {
this.service = this.injector.get<any>(trendyServiceMap[this.use]);
} else {
throw new Error(`There's no such thing as '${this.use}'`);
}
}
一般的に、Angular2のドキュメントには同じアプローチが記載されています。 InjectorComponent
_@Component({
providers: [Car, Engine, Tires, heroServiceProvider, Logger]
})
export class InjectorComponent {
car: Car = this.injector.get(Car);
heroService: HeroService = this.injector.get(HeroService);
hero: Hero = this.heroService.getHeroes()[0];
constructor(private injector: Injector) { }
}
_
コンストラクターにInjector
を注入し、_@Component
_アノテーションのproviders
プロパティにすべてのサービスをリストする必要があります。次に、injector.get(type)
を実行します。type
は_@Input
_から解決されます。ドキュメントによると、Service
は実際に要求されるまで挿入されません(.get()
)。
@ angular/coreモジュールにInjectという名前のサービスがあります。 @Injectを使用すると、代替の注入方法を実現できます。しかし、それはコンストラクターでのみ可能です。
したがって、コンポーネントの入力を@componentデコレータの入力配列に配置し(クラス内で@Inputデコレータを使用しないでください)、コンストラクタにその入力変数を注入する必要があります。