Is there a way to inject a dependency into a decorator factory, using Angular's DI? Let's take the following code as a simplified example:
@Component({
selector: 'hello-component',
template: '<div>Hello World</div>'
})
export class HelloComponent {
@PersonName()
name: string;
ngAfterViewInit() {
console.log(`Hello, ${this.name}`);
}
}
Here, the intended behaviour of the PersonName
decorator is for it to access a Person
dependency, and use it to set the name
property of the class.
Is it possible at all to implement the PersonName
decorator for the code above?
Currently, to inject dependencies into my decorators (and other extra module classes) I'm using this workaround:
import {Injectable, Injector} from "@angular/core";
@Injectable()
export class ExtraModuleInjector {
private static injector;
public static get(token: any) {
if (ExtraModuleInjector.injector) {
return ExtraModuleInjector.injector.get(token);
}
}
constructor(public injector: Injector) {
ExtraModuleInjector.injector = injector;
}
}
After being injected to root component, it allows to use static get method to get dependencies during runtime functions execution. Still looking for better solution.
It's a bit tricky to do this, because decorators are executed at build time, not at the runtime. When decorator is executed, there's no instance of the class.
Back in ng2.beta.10, I used this to get the data from service (don't think you can from component, but I could be wrong...):
// some-route.ts
@CanActivate((next, prev) => {
let store: any = getSingleton(Store);
})
// injector.ts
import {Injector} from 'angular2/core'
let appInjectorRef: Injector;
export const appInjector = (injector?: Injector) => {
if (injector)
appInjectorRef = injector;
return appInjectorRef;
}
export function getSingleton(token: any) {
let injector: Injector = appInjector();
return injector.get(token);
}
..to be honest, looking at this code now I have no ide how it works (; But I know it did back then. Not sure what's the status now, or if there were any breaking changes since beta.10 related to the Injector and ApplicationRef...
One way to do it in Angular 7 is:
app.module.ts
import { setInjector } from './service/inj.service';
@NgModule({..})
export class AppModule {
constructor(i: Injector) {
setInjector(i)
}
}
decorator.service.ts
import { Injectable, Injector } from '@angular/core';
let injector: Injector;
export const setInjector = (i: Injector)=>{
injector = i
}
export function mydecorator(arg:any){
let service: SomeServiceWhichNeedsToBeInjected
return (target, key, descriptor)=>{
if(descriptor === undefined) {
descriptor = Object.getOwnPropertyDescriptor(target, key)
}
var originalMethod = descriptor.value
descriptor.value = function () {
if(!loading){
service= injector.get(SomeServiceWhichNeedsToBeInjected)
}
//do something with service
return originalMethod.apply(this, arguments)
}
return descriptor;
}
}
other.service.ts
@mydecorator('somearg')
decoratedmethod(arg1){
//..
}
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