web-dev-qa-db-fra.com

Injection de dépendances dans la classe abstraite TypeScript (Angular2)

J'ai une classe abstraite (sans constructeur) et je veux y injecter une autre classe.

Classe abstraite:

import { ErrorHandler } from '../../shared/services/errorHandler.service';
import { Inject } from '@angular/core';


export abstract class BaseApiComponent<T> {
    @Inject(ErrorHandler) errorHandler: ErrorHandler;

    this.errorHandler.test();
}

Classe injectée:

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

@Injectable()
export class ErrorHandler  {
  constructor() { }


  public test() {
    console.log('Test');
  }

}

Et j'ai la prochaine erreur

ORIGINAL EXCEPTION: TypeError: Cannot read property 'test' of undefined

Comment puis-je résoudre ce problème?

15
Max K

À partir de Angular 2 RC5 le DI devient plus simple. Vous n'avez pas besoin de décorer le truc avec @Injectable(). Au lieu de cela, vous le déclarez simplement pour DI en un seul endroit - NgModule .

export class ErrorHandler {
    test() {
        console.log('ErrorHandler.test()');
    }
}

export abstract class BaseApiComponent<T> {
    // use protected property parameter in abstract class
    // for accessibility from descendants.
    constructor(protected errorHandler: ErrorHandler) {}

    someMethod() {
        this.errorHandler.test();
    }
}

export class ApiComponentImpl<T> extends BaseApiComponent<T> {
    // use @Inject decorator
    constructor(@Inject(ErrorHandler) errorHandler: ErrorHandler) {
        super(errorHandler);
    }
}

app.module.ts:

// class declarations
@NgModule({
    providers: [
        ErrorHandler,
        ApiComponentImpl
    ]
})
export class AppModule{
}

// bootstrap the app
platformBrowserDynamic().bootstrapModule(AppModule);

Vous pouvez utiliser OpaqueToken pour améliorer la modularité et supprimer la dépendance de type:

export const errorHandlerToken = new OpaqueToken('ErrorHandler');

dans le module:

    providers: [
        // using OpaqueTokens you can change the provided value
        // to anything without changing consumer code 
        {provide: errorHandlerToken, useClass: ErrorHandler},

constructeur:

    constructor(@Inject(errorHandlerToken) errorHandler: ErrorHandler) {
18
Distagon

Angular DI prend uniquement en charge l'injection de constructeur, ce qui signifie que vous avez besoin d'un constructeur.

Vous ne pouvez pas non plus injecter directement dans une classe abstraite car une classe abstraite n'est pas censée être instanciable.

Par conséquent, cela doit être comme:

export abstract class BaseApiComponent<T> {
    constructor(errorHandler: ErrorHandler) {}

    someMethod() {
     this.errorHandler.test();
    }
}

export class ApiComponentImpl<T> {
    constructor(errorHandler: ErrorHandler) {
      super(errorHandler);
    }

}
8
Günter Zöchbauer

Je ne suis pas un développeur angular, mais en regardant les exemples, le décorateur @Inject Est toujours utilisé comme décorateur de paramètres et non comme - décorateur immobilier .

Comme les deux types de décorateurs sont différents, cela pourrait causer le problème, mais je ne suis pas sûr.
Essayer:

export abstract class BaseApiComponent<T> {
    private errorHandler: ErrorHandler;

    protected constructor(@Inject(ErrorHandler) handler) {
        this.errorHandler = handler;
    }

    public error() {
        this.errorHandler.test();
    }
}

De plus, je ne sais pas quand vous utilisez réellement this.errorHandler.test(); car il ne peut pas rester là dans la classe, je l'ai déplacé dans la méthode error.


éditer

Droite. Vous devrez injecter dans la classe d'extension, puis passer l'instance au parent:

export abstract class BaseApiComponent<T> {
    protected errorHandler: ErrorHandler;

    protected constructor(handler: ErrorHandler) {
        this.errorHandler = handler;
    }
}

export class Restaurants extends BaseApiComponent<any> {
    constructor(@Inject(ErrorHandler) handler) {
        super(handler);
    }
}
2
Nitzan Tomer