2

Within Angular I have child component which inherits from a parent component. This parent component injects multiple classes. I want to extend the child component with an injection class which I do not use in the parent class. Before this extension it was not required to instantiate the constructor and call super( *args* ). When I try to extend the constructor though, I get the following error message:

Constructors for derived classes must contain a 'super' call

Is there a way not to be required to call the super class while extending the class with an injection? Let me know if something is not clear about this question.

Parent component

@Component({ template: '' })
export abstract class ParentComponent<T> implements OnInit, OnDestroy {

  constructor(
    protected formBuilder: FormBuilder,
    protected route: ActivatedRoute,
    protected snackBar: MatSnackBar,
    protected location: Location
  ) {
    const routeParams = this.route.snapshot.params;
    if (routeParams && routeParams.id) {
      this.subjectId = this.route.snapshot.params.id;
    }
  }
}

Child component

export class ChildComponent extends ParentComponent<MyT> {
  constructor(
    /** I want to extend with the following service */
    protected myService: Service
  ) {
       // But as I instantiate this constructor, I also need to call super() with the required params
  }
}

Question extension

To extend my question; I am not sure if this double importing of the super class parameters and passing it is overhead. The main reason for this question is because I try to keep the code as clean as possible and try to overcome duplicate code. Duplicate importation of the injection classes for the sake of providing it in the super call feels a bit useless.

Klyner
  • 3,983
  • 4
  • 26
  • 50
  • Why is calling super a problem for you? Maybe there is a different solution that can achieve your goal. – igg Jan 29 '20 at 14:15
  • I don't believe there is a way, you will have to inject all the parents dependencies in the child constructor and pass them to the parent with super(). – Jason White Jan 29 '20 at 14:15

2 Answers2

2

I suppose you are afraid of injecting all the things to you parent. That is why you need that behavior. I'm afraid there is no such option with angular DI. The best thing you can do is common style for all components to inject Injector instead of its dependencies and then getting all the dependencies through injector.

 class Parent {
   private myService = this.injector.get(MyService)
     private myService2 = this.injector.get(MyService2)
   constructor(@Inject(INJECTOR) injector: Injector){}
}
class Child extends Parent {
 constructor(@Inject(INJECTOR) injector: Injector) {
 super(injector);
  }
}

if Parent is not a component in all of this cases you can omit @Inject(INJECTOR) in its constructor

Andrei
  • 10,117
  • 13
  • 21
  • 1
    In this situation, the child will not have `myService` and `myService2`, correct? – igg Jan 29 '20 at 14:24
  • 1
    no, they are `private`. mark them as `protected` at least and then they will be available in all its children – Andrei Jan 29 '20 at 14:26
  • No, `private` is good. I think this is what the OP wants, to inherit the rest of the parent's properties, but not inject the same services. – igg Jan 29 '20 at 14:30
  • 1
    I think that question author doesn't want to reinject all the same services in descendants, so protected is just the best option for this case – Andrei Jan 29 '20 at 14:32
1

After reading your question a few times, I'm not sure that this is understood so I will post it as an answer.

You can extend your parent class and add a service, but you still need to call the parent's constructor. This is unavoidable. You don't need to re-inject anything, although you still need to declare them, at least.

Your child's constructor should look like this:

constructor(
  formBuilder: FormBuilder,
  route: ActivatedRoute,
  snackBar: MatSnackBar,
  location: Location,
  protected myService: Service // note the "protected" here but not above
) {
  super(formBuilder, route, snackBar, location);
}

The non-protected arguments of the child constructor are essentially "pass-throughs", so to speak, to your parent's declarations of what should be injected. There is nothing being double-injected or anything like that.

Zircon
  • 4,677
  • 15
  • 32
  • The target of the question is indeed whether or not it is required to call the parent's constructor in case you want to extend it. And `no` is a valid answer to this question. Thank you! – Klyner Jan 29 '20 at 14:38