Search code examples
angulartypescriptdependency-injectionabstract-class

Dependency injection into abstract class typescript(Angular2)


I have abstract class(without constructor) and I want to inject another class into it.

Abstract class:

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


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

    this.errorHandler.test();
}

Injected class:

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

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


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

}

And I have next error

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

How i can fix this?


Solution

  • As of Angular 2 RC5 the DI becomes simpler. You don't need to decorate the stuff with @Injectable(). Instead, you just declare it for DI in one place - 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);
    

    You can employ OpaqueToken to improve modularity and remove type dependency:

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

    in the module:

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

    constructor:

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