web-dev-qa-db-ja.com

依存性注入でコンポーネントを拡張する方法は?

次のクラスModuleWithHttpがあります。

@Injectable()
export default class {
  constructor(private fetchApi: FetchApi) {}
}

そして、私はそれを次のように使いたい:

@Component({
  selector: 'main',
  providers: [FetchApi]
})
export default class extends ModuleWithHttp {
  onInit() {
    this.fetchApi.call();
  }
}

そのため、既に依存関係を注入しているスーパークラスを拡張することで、その子にアクセスできるようにします。

コンポーネントとしてスーパークラスを持っていても、私は多くの異なる方法を試しました:

@Component({
  providers: [FetchApi]
})
export default class {
  constructor(private fetchApi: FetchApi) {}
}

それでも、 this.fetchApiは、スーパークラスであってもnullです。

31
Kamil Lelonek

スーパークラスにfetchAPIを注入し、それを子クラスに渡す必要があります

export default class extends ModuleWithHttp {

  constructor(fetchApi: FetchApi) {
     super(fetchApi);
  }   

  onInit() {
    this.fetchApi.call();
  }
}

これは、一般的なDIの機能の特徴です。スーパークラスは、継承を介して子をインスタンス化しますが、必要なパラメーターを子に提供する必要があります。

38
TGH

親クラスのコンストラクターでの注入のためだけに子クラスでサービスを注入するこの「ボイラープレート」コードを回避し、継承を通じて子クラスでそのサービスを効果的に使用する場合、これを行うことができます。

編集:from Angular 5.0.0 ReflectiveInjectorはStaticInjectorの代わりに廃止されました。この変更を反映するために以下のコードが更新されます

深さのあるサービスマップを用意し、

export const services: {[key: string]: {provide: any, deps: any[], useClass?: any}} = {
  'FetchApi': {
    provide: FetchApi,
    deps: []
  }
}

インジェクターホルダーを持っている、

import {Injector} from "@angular/core";

export class ServiceLocator {
  static injector: Injector;
}

appModuleで設定し、

@NgModule(...)
export class AppModule {
  constructor() {
    ServiceLocator.injector = Injector.create(
      Object.keys(services).map(key => ({
        provide: services[key].provide,
        useClass: services[key].provide,
        deps: services[key].deps
      }))
    );
  }
}

親クラスでインジェクターを使用し、

export class ParentClass {

  protected fetchApi: FetchApi;

  constructor() {
    this.fetchApi = ServiceLocator.injector.get(FetchApi);
    ....
  }
}

FetchApiサービスを注入する必要がないように、親クラスを拡張します。

export class ChildClass extends ParentClass {
  constructor() {
    super();
    ...
  }

  onInit() {
    this.fetchApi.call();
  }
}
67
Petr Marek

応答が遅れるかもしれませんが、BaseComponentおよびすべてのサブクラスでインジェクターのみをインジェクトすることを解決したため、サービスロケーターを維持する必要はありません。

私の基本クラス:

constructor(private injectorObj: Injector) {

  this.store = <Store<AppState>>this.injectorObj.get(Store);
  this.apiService = this.injectorObj.get(JsonApiService);
  this.dialogService = this.injectorObj.get(DialogService);
  this.viewContainerRef = this.injectorObj.get(ViewContainerRef);
  this.router = this.injectorObj.get(Router);
  this.translate = this.injectorObj.get(TranslateService);
  this.globalConstantsService = this.injectorObj.get(GlobalConstantsService);
  this.dialog = this.injectorObj.get(MatDialog);
  this.activatedRoute = this.injectorObj.get(ActivatedRoute);
}

私の子供のクラス:

constructor( private injector: Injector) {

   super(injector);

}
22
Rogerio