问题
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?
回答1:
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.
回答2:
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...
回答3:
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){
//..
}
回答4:
You can do following:
export class AnnotationExample {
@PersonName
name: string;
constructor() {
alert(this.name);
}
}
function PersonName(/*target: Function, fnName: string, fn: any*/) {
return {value: 'amit'};
}
var whatIs = new AnnotationExample();
来源:https://stackoverflow.com/questions/37906632/angular-2-inject-a-dependency-into-a-decorator-factory