web-dev-qa-db-fra.com

Comment étendre un composant avec injection de dépendance?

J'ai la classe suivante ModuleWithHttp:

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

et je veux l'utiliser comme suit:

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

Donc, en étendant une super classe qui injecte déjà une dépendance, je veux avoir un accès à celle-ci à ses enfants.

J'ai essayé de nombreuses manières différentes, même avec la super classe comme composant:

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

Mais reste, this.fetchApi est null, même en super-classe.

31
Kamil Lelonek

Vous devez injecter fetchAPI dans la super classe et le transmettre à la classe enfant.

export default class extends ModuleWithHttp {

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

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

Ceci est une caractéristique du fonctionnement de DI en général. La super classe instanciera l'enfant via l'héritage, mais vous devez lui fournir les paramètres requis.

38
TGH

Si vous voulez éviter ce code de "plaque de chaudière", injectez des services dans des classes enfants uniquement pour une injection dans le constructeur des classes parents et utilisez ensuite efficacement ces services dans des classes enfants par héritage, vous pouvez procéder comme suit:

edit: from Angular 5.0.0 ReflectiveInjector est obsolète en faveur de StaticInjector, le code ci-dessous est mis à jour pour refléter ce changement)

Avoir une carte des services avec les dépends,

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

Avoir un porte-injecteur,

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

export class ServiceLocator {
  static injector: Injector;
}

configurez-le dans 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
      }))
    );
  }
}

utiliser l'injecteur en classe parente,

export class ParentClass {

  protected fetchApi: FetchApi;

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

et étendre la classe parent afin que vous n'ayez pas besoin d'injecter le service FetchApi.

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

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

Réponse tardive peut-être, mais j'avais résolu d'injecter uniquement l'injecteur sur le composant de base et dans toutes les sous-classes. De cette manière, je n'ai pas besoin de maintenir un localisateur de service.

Ma classe de base:

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

Mes classes d'enfant:

constructor( private injector: Injector) {

   super(injector);

}
22
Rogerio