2

Normally, when you have some injectable service you wnat to use, you write something like this:

export class MyClass {
 constructor(
                private _myservice: MyService)
  { }
  [...]
}

Unfortunally, when you extends MyClass, the child constructor, when calling super, needs to inject the same service.

export class MyClassSon extends MyClass {
   constructor()
   {
       super(); <<<---- ERROR!!!!
   }

I'm confusing. Im using SuperClass to allow sub-class to access injectable-services without inject them themself.

The best solution I found is Injector:

export class MyClass {
     constructor(
                    injector: Injector)
      { 
          this._myservice = injector.get(MyService);
          this._fooservice = injector.get(FooService);
          //others services...
    }
}

export class MyClassSon extends MyClass {
       constructor(injector: Injector)
       {
           super(injector);
           //I can use any other services
       }

This minimize the complexity of super-call but I'm still pissed off I need to do this trick.

Is there another way to Inject something in class without using costructor so I can leave it as clean as possible and only for specific components initialization?

EviSvil
  • 510
  • 3
  • 21
  • Do you need services, in `MyClassSon` that you don't need in `MyClass`? – Nicolas Nov 20 '19 at 17:13
  • Injecting via the constructor is what you always do when the service has no superclass. Why would it be different when the service has a superclass? Just do the easy, simple, natural, trivial, testable thing: inject via the constructor, and call super() with the required arguments. Or use delegation rather than inheritance. – JB Nizet Nov 20 '19 at 17:14
  • @Nicolas MyClass is an entry point so every component extending it, has access to all services. If a sub-class needs a specific service, it will inject it for itself only. I think I don't get your question. – EviSvil Nov 20 '19 at 17:23
  • Does this answer your question? [Inheritance and dependency injection](https://stackoverflow.com/questions/39038791/inheritance-and-dependency-injection) – Darren Ruane Nov 20 '19 at 17:24
  • You should never use inheritance for components – HTN Nov 20 '19 at 20:05

1 Answers1

0

If you absolutely want to keep your constructor clean, you can use injector from static field of your CoreModule (for example). This is not recommended but it works.

First you should have to retrieve your Injector from your CoreModule/AppModule (root)

export class CoreModule {
  public static injector: Injector;

  public constructor(injector: Injector) {
    CoreModule.injector = injector;
  }
}

inside MyClass

export class MyClass {
  public constructor() {
    this.myService = CoreModule.injector.get(MyService)
  }
}

inside MyClassSon

export class MyClassSon extends MyClass {
  public constructor() {
    super(); // required for invoke parent build
  }
}

you can use another alternative inside MyClass that don't need to invoke super() constructor from child.

export class MyClass implements OnInit {
  public ngOnInit() {
    this.myService = CoreModule.injector.get(MyService)
  }
}

but with the last one be careful to not override in the child the ngOnInit method without call the parent one.

This solution is not best practice compliant but works fine.


Edit

Working with abstract class.

export abstract class MyClass {
  protected abstract get myService();
}
export class MyClassSon extends MyClass {
  protected get myService() {
    return this._myService;
  }

  public construction(private _myService: MyService) {

  }
}
Romain
  • 91
  • 3
  • Hi! Thank you for you answer. This is cleaner than the solution im using with injector in constructor. One more question: You said is not a best practice. Which Design Patter we have to use in this case? How can you centralize all injection to use in sub-classes? – EviSvil Nov 21 '19 at 08:23
  • I'm not sure that there is a pattern for this solution. But it could be a combination of patterns. I'm thinking of inheritance, singleton & dependency injection. You can make something smarter by making MyClass abstract and let the MyClassSon providing the service (i modified my post) – Romain Nov 21 '19 at 09:07
  • Im using static injector solution but I can't find a way to load it in app.module.ts. If I treat it like a Component, it require "@component" and a template. If I treat it like module, it require NgModule. Without including it in app.module, in MyClass CoreModule.injector is undefined – EviSvil Nov 27 '19 at 13:27
  • You should use NgModule. First, you should create CoreModule (a NgModule) and import it inside your AppModule (the root NgModule). Then with the CoreModule constructor, you can retrieve the Injector and link it to your static field (inside the CoreModule). – Romain Nov 28 '19 at 14:06