在没有构造函数注入的情况下获取服务实例


81

@Injectable在引导程序中定义了一项服务。我想在不使用构造函数注入的情况下获取服务实例。我尝试使用,ReflectiveInjector.resolveAndCreate但这似乎创建了一个新实例。

我要这样做的原因是我有一个由许多组件派生的基本组件。现在,我需要访问一个服务,但是我不想将其添加到ctor中,因为我不想在所有派生组件上注入该服务。

TLDR:我需要一个 ServiceLocator.GetInstance<T>()

更新: RC5 +的更新代码:存储进样器实例以在组件中使用

Answers:


72

是的,ReflectiveInjector.resolveAndCreate()创建一个新的未连接的注射器实例。

您可以使用以下方法注入AngularsInjector实例并从中获取所需实例

constructor(private injector:Injector) {
  injector.get(MyService);
}

您还可以Injector在一些全局变量中存储,然后使用该注入器实例获取提供的实例,例如https://github.com/angular/angular/issues/4112#issuecomment-153811572


1
在bootstrap.then()的全局变量中存储注射器,听起来像我需要的。
dstr

65
问题说没有构造函数会使这个答案变得毫无帮助。
乔纳森·迈尔斯

1
如果构造函数在组件中,则是组件注入器,在服务中,是模块注入器(如果不是延迟加载的模块,则基本上是根注入器)。您还可以通过添加来获取父组件注入器@SkipSelf()。您也可以插入parent吸气剂,以获得根注入器。
君特Zöchbauer

2
@Rhyous魔术?您可以在静态字段或全局变量中共享注入器,然后从那里访问它,但是首先您需要使用构造函数在某个位置注入它,并将其分配给静态域。
君特Zöchbauer

1
DI容器ng使用的不好吗,甚至不支持普通DI容器的基本功能?
Rhyous

61

在使用ngModules的更新的Angular中,您可以在代码中的任何位置创建一个变量:

export let AppInjector: Injector;

export class AppModule {
  constructor(private injector: Injector) {
    AppInjector = this.injector;
  }
}

现在,您可以使用AppInjector来在代码的任何位置查找任何服务。

import {AppInjector} from '../app.module';

const myService = AppInjector.get(MyService);

1
真好 可能也是stackoverflow.com/questions/39409328/…的一个很好的答案。
Arjan

1
你是国王!
Davide Perozzi

哇,我们可以这样做吗?
Simon_Weaver

2
这有一个小问题。您必须为提供服务的延迟加载模块制作单独的注入器。
Vahid

7

另一种方法是定义一个自定义装饰器(CustomInjectable用于为依赖项注入设置元数据:

export function CustomComponent(annotation: any) {
  return function (target: Function) {

    // DI configuration
    var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
    var parentAnnotations = Reflect.getMetadata('design:paramtypes', parentTarget);

    Reflect.defineMetadata('design:paramtypes', parentAnnotations, target);

    // Component annotations / metadata
    var annotations = Reflect.getOwnMetadata('annotations', target);
    annotations = annotations || [];
    annotations.push(annotation);
    Reflect.defineMetadata('annotations', annotations, target);
  }
}

它将利用来自父构造函数的元数据,而不是其自身的元数据。您可以在子类上使用它:

@Injectable()
export class SomeService {
  constructor(protected http:Http) {
  }
}

@Component()
export class BaseComponent {
  constructor(private service:SomeService) {
  }
}

@CustomComponent({
  (...)
})
export class TestComponent extends BaseComponent {
  constructor() {
    super(arguments);
  }

  test() {
    console.log('http = '+this.http);
  }
}

有关更多详细信息,请参见此问题:


2
问题是tsc不允许我调用super(arguments),因为基本构造函数的参数不匹配。
议会

1
在那种特殊情况下,我们可以从派生类github.com/Microsoft/TypeScript/issues/12439中
slowkot

-1

StoreService .ts

  import { Injectable} from '@angular/core';

    @Injectable()
    export class StoreService {
      static isCreating: boolean = false;
      static instance: StoreService ;

      static getInstance() {
        if (StoreService.instance == null) {
          StoreService.isCreating = true;
          StoreService.instance = new StoreService ();
          StoreService.isCreating = false;
        }
        return StoreService.instance;
      }
      constructor() {
        if (!StoreService.isCreating) {
          throw new Error('You can\'t call new in Singleton instances! Call StoreService.getInstance() instead.');
        }
     }

  MyAlertMethod(){
    alert('hi);
    }
  }

component.ts

//call this service directly in component.ts as below:-

 StoreService.getInstance().MyAlertMethod();

这如何与需要在构造函数中注入其他服务的服务一起使用?
Emeke Ajeh '20
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.