2016-12-28 15 views
10

コンポーネントが@Input()によって決定される注入された依存関係を必要とするAngular 2のコンポーネントディレクティブがあるとします。@Input()に基づく角度2の動的依存性注入

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

私は、これは技術的に働くだろうと思うが、動的な依存性の注入を行うには良い方法があるように持っています。

答えて

4

これは、@角度/コアモジュールに注入するというサービスがあります

// 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}'`); 
    } 
} 
+0

4.0以降、 'get'は非推奨です。 –

+0

私は署名を意味します。 https://github.com/angular/angular/blob/5.2.5/packages/core/src/di/injector.ts#L62 –

+0

を参照してください。ジェネリックメソッドを型で呼び出す方が常に良いです。この署名が削除されるかどうかはわかりません。ジェネリックを使用する方が良いことをユーザーに知らせるためにそこにあります。いずれにせよ、私は注意を払って、答えを更新しました。通常、私はソリューションの徹底的なタイピングを心配することなく、その要点を提供することに集中します。 – estus

2

です。 @Injectを使用すると、別の方法で注入することができます。しかし、それはコンストラクタでのみ行うことができます。

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

+1

私も注射に投票します: 親コンポーネント内の異なるサービスで、流行りのディレクティブを複数回使用するのですか、動的に切り替えますか?そうでない場合、親コンポーネントは適切なサービスを提供するだけで、複雑なロジックを実装する必要はありません。 ({myServiceInterfase、useClass:MyServiceImpl}}} '' '次に' 'コンストラクタ(private myService:MyServiceInterface){}' @Component({セレクタ: 'i-use-trendy-directive' '' –

+0

私の場合は、別のサービスを持つ複数の場所でディレクティブを使います。ありがとう。 – John

+0

@Vineet 'DEVIN' Dev非常に面白いです。デコレータの入力配列のドキュメントが疎そうです。 '@ Component'デコレータでは、コンポーネントライフサイクルの初期段階で' @ Input'デコレータで指定されているものよりも優先されます。 – John

3

、同じアプローチが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)と入力してください。@Inputからtypeが解決されます。ドキュメントごとに、Serviceはあなたがそれを求めるまで実際には注入されません(.get())。

関連する問題