【问题标题】:Angular | Inject service into decorator角 |将服务注入装饰器
【发布时间】:2019-03-10 22:47:35
【问题描述】:

我正在尝试将服务注入到我正在创建的装饰器函数中,这样我就可以获取存储在变量中的内容。

我目前有一个基本的装饰器设置。

export function canEdit(editName: string, service: Service) {
      return function (constructor: any) {
          console.log(constructor);
      }
}

我在哪里使用它,它要求我输入第二个参数,显然需要注入依赖项。

我还尝试了函数中不允许的@Inject(Service)

有没有办法可以做到这一点?

或者是否可以在装饰器中获取父类变量?

【问题讨论】:

    标签: angular typescript decorator


    【解决方案1】:

    我知道我迟到了,但是,还有另一种方法可以在装饰器中访问服务。

    在需要必要服务的模块中暴露 Angular 的 Injector:

    @NgModule({
      declarations: [],
      imports: [],
      providers: [SomeService]
    })
    export class SharedModule {
      static injector: Injector;
    
      constructor(injector: Injector) {
        SharedModule.injector = injector;
      }
    }
    

    通过模块注入器属性从装饰器内部获取服务:

    export const MyDecorator = (): any => {
    
      return (target: object, key: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor => {
        const originalMethod = descriptor.value;
    
        descriptor.value = function(...args: any[]): any {
          // access the service
          const service = SharedModule.injector.get<SomeService>(SomeService);
    
          // (...)
        };
    
        return descriptor;
      };
    };
    

    【讨论】:

      【解决方案2】:

      装饰器是在 Angular 的依赖注入系统之外工作的 TypeScript 功能。

      我知道的唯一解决方案是创建一个特殊服务,将依赖项暴露给装饰器。

      @Injectable()
      export class DecoratorService {
           private static service: Service | undefined = undefined;
           public constructor(service: Service) {
               DecoratorService.service = service;
           }
           public static getService(): Service {
               if(!DecoratorService.service) {
                   throw new Error('DecoratorService not initialized');
               }
               return DecoratorService.service;
           }
      }
      

      您现在可以通过上述类访问注入的服务。

      export function canEdit(editName: string) {
            return function (constructor: any) {
                const service = DecoratorService.getService();
                // ^^^ access dependency here
                console.log(constructor);
            }
      }
      

      除非 Angular 应用程序中的某些内容依赖于 DecoratorService,否则上述内容将不起作用,因为 Angular 在需要时会创建实例。所以你可以将它注入到一个模块中来强制它被初始化。

      @NgModule({
          provides: [
              DecoratorService
          ]
      })
      export class MainModule {
          public constructor(service: DecoratorService) {
                            // ^^^ forces an instance to be created
          }
      }
      

      【讨论】:

      • 嗨,我遇到的唯一问题是我收到此错误DecoratorService not initialized。我已经把它放在模块里了。
      • @tallent123 表示在模块加载之前正在执行装饰器。你是如何使用装饰器的?
      • 我有一个服务,我在函数 `@CanEdit('this_function') 上方输入。据我所知,该功能是在应用程序初始化之后,因为它实际上并没有被调用,直到您单击主屏幕上的按钮
      • 如果模块在检查装饰器后加载(所有服务定位器都是空的)我没有看到解决方案 =(
      • @ShacharHar-Shuv 如果在依赖项初始化之前调用装饰器......这不会使答案无效吗?
      【解决方案3】:

      Angular Dependancy 注入仅适用于依赖于另一个服务的组件类或 Angular 服务。

      依赖的消费者,即角度组件,在其构造函数中声明它需要什么,并让框架提供它们。

      有关依赖注入的更多信息,请参阅官方 Angular 文档:

      Dependency Injection in action

      https://next.angular.io/guide/dependency-injection-in-action

      【讨论】:

      • 那么有没有办法把这个放到装饰器里面呢?
      猜你喜欢
      • 2018-01-07
      • 2018-07-30
      • 2020-01-18
      • 1970-01-01
      • 2021-07-12
      • 2021-01-30
      • 2021-05-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多