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.
Just use the getter this. aService . They only time this won't work is if you are trying to use AService within the constructor of Bservice , then you would have the same issue of a circular reference since Aservice would not be ready yet. By using the getter you are deferring injecting the service until you need it.
Angular provides the ability for you to inject a service into a component to give that component access to the service. The @Injectable() decorator defines a class as a service in Angular and allows Angular to inject it into a component as a dependency.
@Inject() is a manual mechanism for letting Angular know that a parameter must be injected. It can be used like so: import { Component, Inject } from '@angular/core'; import { ChatWidget } from '../components/chat-widget';
If no Angular decorator has been used on a class there is no way for Angular to read what dependencies it requires. This is why we need to use @Injectable() . If our service injects providers we must add @Injectable() , which providers no extra functionality, to tell Angular to store that metadata it needs.
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().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With