Dependency injection into abstract class typescript(Angular2)
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 appplatformBrowserDynamic().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) {
Angular DI only supports constructor injection, which means you need a constructor.
You also can't inject into an abstract class directly because an abstract class is not supposed to be instantiatable.
Therefore it has to be like:
export abstract class BaseApiComponent<T> { constructor(errorHandler: ErrorHandler) {} someMethod() { this.errorHandler.test(); }}export class ApiComponentImpl<T> { constructor(errorHandler: ErrorHandler) { super(errorHandler); }}
I'm not an angular developer, but looking at the examples the @Inject
decorator is always used as a parameter decorator and not as a property decorator.
As the two decorator types are different, that might cause the problem but I'm not sure.
Try:
export abstract class BaseApiComponent<T> { private errorHandler: ErrorHandler; protected constructor(@Inject(ErrorHandler) handler) { this.errorHandler = handler; } public error() { this.errorHandler.test(); }}
Also I'm not sure when you're actually using this.errorHandler.test();
as it can't just sit there in the class, I moved it into the error
method.
edit
Right. You'll need to inject in the extending class and then pass the instance to the 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); }}