Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency injection into abstract class typescript(Angular2)

Tags:

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?

like image 370
Max K Avatar asked Aug 30 '16 10:08

Max K


People also ask

Can we inject dependency in abstract class?

Yes, you can use an abstract base class to do the same thing, but I'd only use that if there's a common set of functionality I can factor out into the base class to keep my code DRY.

Why abstract classes are not used in Dependency Injection?

Abstract classes are good where we have shared code in the implementations. This lets us put the shared code into the abstract class and all of the child classes can use it (thus, no duplication). We are limited by single inheritance, so we cannot descend from an abstract class and another class at the same time.

Does TypeScript support Dependency Injection?

The D letter in SOLID is the Dependency Inversion principle. It helps to decouple modules from each other so that you can easily swap one part of the code for another. One of the techniques that helps to follow this principle is Dependency Injection.

Can I instantiate an abstract class in TypeScript?

TypeScript has the ability to define classes as abstract. This means they cannot be instantiated directly; only nonabstract subclasses can be.


2 Answers

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) { 
like image 148
Distagon Avatar answered Oct 27 '22 21:10

Distagon


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);     }  } 
like image 27
Günter Zöchbauer Avatar answered Oct 27 '22 20:10

Günter Zöchbauer