コンストラクターを挿入せずにサービスのインスタンスを取得する


81

@Injectableブートストラップで定義されたサービスがあります。コンストラクターインジェクションを使用せずにサービスのインスタンスを取得したい。使ってみましたReflectiveInjector.resolveAndCreateが、新しいインスタンスができたようです。

私がやろうとしている理由は、多くのコンポーネントから派生した基本コンポーネントがあるからです。ここでサービスにアクセスする必要がありますが、すべての派生コンポーネントにサービスを注入したくないため、ctorにサービスを追加したくありません。

TLDR:必要です ServiceLocator.GetInstance<T>()

更新: RC5 +の更新されたコード:コンポーネントで使用するためのインジェクターインスタンスの保存

回答:


72

はい、ReflectiveInjector.resolveAndCreate()接続されていない新しいインジェクターインスタンスを作成します。

AngularsInjectorインスタンスを挿入し、それから目的のインスタンスを取得できます。

constructor(private injector:Injector) {
  injector.get(MyService);
}

また、Injectorをグローバル変数に格納し、このインジェクターインスタンスを使用して、たとえばhttps://github.com/angular/angular/issues/4112#issuecomment-153811572で説明されているように提供されたインスタンスを取得することもできます。


1
bootstrap.then()のグローバル変数にインジェクターを格納すると、必要なもののように聞こえます。
dstr 2016年

65
質問は、この答えをかなり役に立たないものにするコンストラクターなしで言います。
ジョナサンマイルズ

1
コンストラクターがコンポーネント内にある場合、それはコンポーネントインジェクターであり、サービスではモジュールインジェクターです(遅延ロードされたモジュールでない場合は基本的にルートインジェクター)。を追加して、親コンポーネントのインジェクターを取得することもでき@SkipSelf()ます。parentルートインジェクターを取得するために、ゲッターを相互作用させることもできます。
ギュンターZöchbauer

2
@Rhyous magic?インジェクターを静的フィールドまたはグローバル変数で共有し、そこからアクセスできますが、最初にコンストラクターを使用して「どこかに」インジェクターを注入し、静的フィールドに割り当てる必要があります。
ギュンターZöchbauer

1
DIコンテナngは、一般的なDIコンテナの基本機能すらサポートしていないという悪い使い方をしていますか?
Rhyous 2018

61

ngModulesが使用される更新されたAngularでは、コード内の任意の場所で使用可能な変数を作成できます。

export let AppInjector: Injector;

export class AppModule {
  constructor(private injector: Injector) {
    AppInjector = this.injector;
  }
}

これで、を使用しAppInjectorて、コードの任意の場所で任意のサービスを見つけることができます。

import {AppInjector} from '../app.module';

const myService = AppInjector.get(MyService);

1
いいね。stackoverflow.com/questions/39409328/…でも良い答えかもしれません。
Arjan 2017

1
あなたは王様です!
Davide Perozzi 2018

うわー、これを行うことは許可されていますか?
Simon_Weaver

2
これには小さな問題があります。サービスを提供する遅延ロードモジュール用に個別のインジェクターを作成する必要があります。
ヴァヒド

7

別のアプローチは、カスタムデコレータを定義することで構成されます(CustomInjectable依存性注入のメタデータを設定するには:

export function CustomComponent(annotation: any) {
  return function (target: Function) {

    // DI configuration
    var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    var parentAnnotations = Reflect.getMetadata('design:paramtypes', parentTarget);

    Reflect.defineMetadata('design:paramtypes', parentAnnotations, target);

    // Component annotations / metadata
    var annotations = Reflect.getOwnMetadata('annotations', target);
    annotations = annotations || [];
    annotations.push(annotation);
    Reflect.defineMetadata('annotations', annotations, target);
  }
}

独自のコンストラクターではなく、親コンストラクターからのメタデータを活用します。子クラスで使用できます。

@Injectable()
export class SomeService {
  constructor(protected http:Http) {
  }
}

@Component()
export class BaseComponent {
  constructor(private service:SomeService) {
  }
}

@CustomComponent({
  (...)
})
export class TestComponent extends BaseComponent {
  constructor() {
    super(arguments);
  }

  test() {
    console.log('http = '+this.http);
  }
}

詳細については、次の質問を参照してください。


2
問題は、基本コンストラクターの引数が一致しないため、tscでsuper(arguments)を呼び出せないことです。
議会

1
その特定のケースでは、派生クラスgithub.com/Microsoft/TypeScript/issues/12439
slowkot 2017

-1

StoreService .ts

  import { Injectable} from '@angular/core';

    @Injectable()
    export class StoreService {
      static isCreating: boolean = false;
      static instance: StoreService ;

      static getInstance() {
        if (StoreService.instance == null) {
          StoreService.isCreating = true;
          StoreService.instance = new StoreService ();
          StoreService.isCreating = false;
        }
        return StoreService.instance;
      }
      constructor() {
        if (!StoreService.isCreating) {
          throw new Error('You can\'t call new in Singleton instances! Call StoreService.getInstance() instead.');
        }
     }

  MyAlertMethod(){
    alert('hi);
    }
  }

component.ts

//call this service directly in component.ts as below:-

 StoreService.getInstance().MyAlertMethod();

これは、コンストラクターに挿入された他のサービスを必要とするサービスでどのように機能しますか?
EmekeAjeh20年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.