web-dev-qa-db-ja.com

Angular @Input()に基づく2つの動的依存性注入

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

これは技術的にはうまくいくと思いますが、動的な依存性注入を行うより良い方法がなければなりません。

18
John

それは

// 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}'`);
    }
}
10
Estus Flask

一般的に、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())。

5
A. Tim

@ angular/coreモジュールにInjectという名前のサービスがあります。 @Injectを使用すると、代替の注入方法を実現できます。しかし、それはコンストラクターでのみ可能です。

したがって、コンポーネントの入力を@componentデコレータの入力配列に配置し(クラス内で@Inputデコレータを使用しないでください)、コンストラクタにその入力変数を注入する必要があります。

2