gib65
gib65

Reputation: 2019

How do I inject things into a parent class constructor even though I have to call super() in my Angular application?

I'm working with an Angular application and I'm trying to figure something out. I have this code here:

export abstract class ListPageComponent {
  ...
  constructor(protected ngZone: NgZone) {}
  ...
}
export class UserListPageComponent extends ListPageComponent {
  ...
  constructor(protected ngZone: NgZone) {
    super(ngZone);
  }
  ...
}

The issue with this is that this creates two references to ngZone, one in the child and one in the parent. What I'm trying to do is treat ngZone like a member of the parent class that the child has access to (i.e. one reference, not two).

I'm forced to call super(ngZone) because Typescript won't let me leave it out. So I either call super(ngZone) or super(), and in neither case am I'm not injecting ngZone into the parent such that it can be shared between parent and child.

If ngZone could somehow be automatically injected into the parent, that would solve my problem, but I'm not sure how to do that. Any help is much appreciated. Thanks

Upvotes: 0

Views: 1111

Answers (2)

Aviad P.
Aviad P.

Reputation: 32639

What you are specifically asking is, as you said, impossible. Angular will only instantiate concrete classes.

But why do you need inheritance at the component level? I assume you have common functionality you want to share between components. I would change the strategy. Use a transient* service for the shared functionality, instead of a base class (i.e. composition instead of inheritance). Sure, you would still need to inject that service to all of the components who used to inherit from the base class, but it's not so bad, because you would be keeping the shared functionality in one place.

  • Transient service - provide the service by using a factory so that each component instance gets its own instance of the service. This is closest to the original intent of having a base class.
providers: [
  {
    provide: ListPageService,
    useFactory: (zone: NgZone) => new ListPageService(zone),
    deps: [NgZone]
  }
]

Upvotes: 1

Porter
Porter

Reputation: 313

A work around that I would do here would be to create an injectable service that is responsible for creating the shared NgZone class:

import { Injectable, NgZone } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class SharedNgZoneService {
  constructor(public ngZone: NgZone) { }
}

and then consume this service within both your components.

Upvotes: 1

Related Questions