Search code examples
angularinheritanceinjecttypescript1.8

Inheritance and dependency injection


I have a set of angular2 components that should all get some service injected. My first thought was that it would be best to create a super class and inject the service there. Any of my components would then extend that superclass but this approach does not work.

Simplified example:

export class AbstractComponent {
  constructor(private myservice: MyService) {
    // Inject the service I need for all components
  }
}

export MyComponent extends AbstractComponent {
  constructor(private anotherService: AnotherService) {
    super(); // This gives an error as super constructor needs an argument
  }
}

I could solve this by injecting MyService within each and every component and use that argument for the super() call but that's definetly some kind of absurd.

How to organize my components correctly so that they inherit a service from the super class?


Solution

  • Updated solution, prevents multiple instances of myService being generated by using the global injector.

    import {Injector} from '@angular/core';
    import {MyServiceA} from './myServiceA';
    import {MyServiceB} from './myServiceB';
    import {MyServiceC} from './myServiceC';
    
    export class AbstractComponent {
      protected myServiceA:MyServiceA;
      protected myServiceB:MyServiceB;
      protected myServiceC:MyServiceC;
    
      constructor(injector: Injector) {
        this.settingsServiceA = injector.get(MyServiceA);
        this.settingsServiceB = injector.get(MyServiceB);
        this.settingsServiceB = injector.get(MyServiceC);
      }
    }
    
    export MyComponent extends AbstractComponent {
      constructor(
        private anotherService: AnotherService,
        injector: Injector
      ) {
        super(injector);
    
        this.myServiceA.JustCallSomeMethod();
        this.myServiceB.JustCallAnotherMethod();
        this.myServiceC.JustOneMoreMethod();
      }
    }
    

    This will ensure that MyService can be used within any class that extends AbstractComponent without the need to inject MyService in every derived class.

    There are some cons to this solution (see Ccomment from @Günter Zöchbauer below my original question):

    • Injecting the global injector is only an improvement when there are several different services that need to be injected in many places. If you just have one shared service then it's probably better/easier to inject that service within the derived class(es)
    • My solution and his proposed alternative have both the disadvantage that they make it harder to see which class depends on what service.

    For a very well written explanation of dependency injection in Angular2 see this blog post which helped me greatly to solve the problem: http://blog.thoughtram.io/angular/2015/05/18/dependency-injection-in-angular-2.html