Reputation: 6294
I have components B
, C
, D
that inherit from class A
.
I want to use a service in class A
, but I don't know how to inject it, without injecting it from its children.
What I tried is a normal injection:
constructor(pageName: string = null, translate: TranslateService) {
But when I do super()
to construct class A
, it throws an error because I didn't supply a second parameter.
Is there a way to inject into a parent class using Angular 2?
The Angular version I am forced to use is: 2.2.1
Some example case: I have many pages, each can show a loader. Instead of injecting the loader every time, and manage the loader from every page, I want to do:
export class BaseComponent {
constructor(private loader: LoadingService) {}
showLoading() {
this.loader.show();
}
}
And then to inherit from the component itself:
@Component({
selector: "page-login",
providers: [UsersService],
templateUrl: "login.html"
})
export class LoginPage extends BaseComponent {
constructor(private usersService: UsersService) {
super();
}
}
Now LoginPage
has a method showLoading
from it's parent.
Upvotes: 48
Views: 43756
Reputation: 1138
For Angular 14 and above there is inject()
function:
import {inject} from '@angular/core'
export class BaseComponent {
public loader;
constructor() {
this.loader = inject(LoadingService)
}
showLoading() {
this.loader.show();
}
}
export class LoginPage extends BaseComponent {
constructor(private usersService: UsersService) {
super();
}
}
This way LoadingService
will be available in your both (parent & child) components and UsersService
only in your child component.
If you want LoadingService
to be available only in the BaseComponent
, just set private loader
.
Upvotes: 12
Reputation: 6963
Take a look at this code.
@Injectable({ providedIn: "root" })
export class MyService {
constructor(...) {
MyService.ms = this;
}
static ms: MyService;
This works because Angular creates singleton instances. The only requirement is that a component somewhere prior to using the variable ms, must have used MyService in the CTOR.
Like this:
@Component
export class MyComponent {
//this will set the static value
constructor(private MyService) { }
...
Upvotes: 2
Reputation: 554
In my case in Angular 10 running 'ng serve --aot', I had to use:
export class BaseComponent {
public loader;
constructor()
{
setTimeout(() => {
this.loader = ServiceLocator.injector.get(LoadingService);
}, 0);
}
showLoading() {
this.loader.show();
}
}
This because it seems that now the code in the service constructor is executed first and then the constructor in the module which assigns the Injector instance to the ServiceLocator service, leading to the ServiceLocator.injector to be undefined if the setTimeout() hack is not used. Any ideas on how to improve this?
Upvotes: 0
Reputation: 4912
You could solve this by using a service locator service. That will easily allow you to get any service and use it in your parent classes without having to inject them via their children (as this can be a pain).
So to use this, create a simple class locator.service.ts:
import {Injector} from "@angular/core";
export class ServiceLocator {
static injector: Injector;
}
Import this service in your app.module.ts:
import {ServiceLocator} from './locator.service';
Then in the constructor of your module file (app.module.ts?), init this thing so you can use it anywhere:
export class AppModule {
constructor(private injector: Injector){ // Create global Service Injector.
ServiceLocator.injector = this.injector;
}
}
Now, to use it in your super class (your BaseComponent), simply import the ServiceLocator
import {ServiceLocator} from './locator.service';
and use it like:
export class BaseComponent {
public loader;
constructor() {
this.loader = ServiceLocator.injector.get(LoadingService)
}
showLoading() {
this.loader.show();
}
}
Now you have injected your service in an extendable parent and it's usable in your child components without having to pass it in the super().
Upvotes: 100