Angular 2 - Inject a dependency into a decorator factory

余生长醉 提交于 2019-12-23 07:39:22

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!