存储注入器实例以在组件

时间:2016-09-09 10:21:07

标签: angular

在RC5之前我使用appref injector作为服务定位器,如下所示:

Startup.ts

bootstrap(...)
.then((appRef: any) => {
    ServiceLocator.injector = appRef.injector;
});

ServiceLocator.ts

export class ServiceLocator {
    static injector: Injector;
}

成分:

let myServiceInstance = <MyService>ServiceLocator.injector.get(MyService)

现在在bootstrapModule()中执行相同操作。然后()不起作用,因为组件似乎在promise之前开始执行。

有没有办法在组件加载之前存储注入器实例?

我不想使用构造函数注入,因为我在基础组件中使用了注入器,这是由许多组件派生的,我宁愿不将注入器注入所有组件。

4 个答案:

答案 0 :(得分:31)

对于今天的TypeScript和Angular 5,在导入全局注入器时避免WARNING in Circular dependency detected,首先声明一个帮助器,例如app-injector.ts

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

/**
 * Allows for retrieving singletons using `AppInjector.get(MyService)` (whereas
 * `ReflectiveInjector.resolveAndCreate(MyService)` would create a new instance
 * of the service).
 */
export let AppInjector: Injector;

/**
 * Helper to set the exported {@link AppInjector}, needed as ES6 modules export
 * immutable bindings (see http://2ality.com/2015/07/es6-module-exports.html) for 
 * which trying to make changes after using `import {AppInjector}` would throw:
 * "TS2539: Cannot assign to 'AppInjector' because it is not a variable".
 */
export function setAppInjector(injector: Injector) {
    if (AppInjector) {
        // Should not happen
        console.error('Programming error: AppInjector was already set');
    }
    else {
        AppInjector = injector;
    }
}

接下来,在AppModule中,使用以下方式设置:

import {Injector} from '@angular/core';
import {setAppInjector} from './app-injector';

export class AppModule {
    constructor(injector: Injector) {
        setAppInjector(injector);
    }
}

如果需要,请使用:

import {AppInjector} from './app-injector';
const myService = AppInjector.get(MyService);

答案 1 :(得分:8)

我设法使用手动增强功能来完成它。不要使用&#34; bootstrap: [AppComponent]&#34; @NgModule中的声明,请改用ngDoBootstrap方法:

export class AppModule {
    constructor(private injector: Injector) {
    }

    ngDoBootstrap(applicationRef: ApplicationRef) {
        ServiceLocator.injector = this.injector;
        applicationRef.bootstrap(AppComponent);
    }
}

答案 2 :(得分:3)

另一种角度为2.0.0的解决方案:

platformBrowserDynamic().bootstrapModule(AppModule, [
  {
    defaultEncapsulation: ViewEncapsulation.Emulated,
    providers: [
      { provide: TRANSLATIONS, useValue: TRANSLATION },
      { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' },
      { provide: LOCALE_ID, useValue: 'fr' }
    ]
  }
]).then((modref: NgModuleRef<any>) => {
  appInjector(modref.injector);
});

答案 3 :(得分:0)

基于类的解决方案。

通常,我需要从其他类使用的类中引用服务。 通过构造函数注入服务很麻烦,并且会导致不需要给定服务的调用类出现问题。

在Angular 8中,我设置了一个库类:ServiceInjectorModule (也可以在子模块内部使用)

(源自关于stackoverflow的类似答案)

文件:service-injector.module.ts

import { NgModule, Injector } from '@angular/core';

export let ServiceInjector: Injector;

@NgModule()
export class ServiceInjectorModule {
  constructor(private injector: Injector) {
    ServiceInjector = this.injector;
  }
}

文件:my-lib.module.ts

注意:您可以跳过此库模块,因为只有在要使用其他服务或模块的情况下,这样做才更加方便。如果您跳过它,则将ServiceInjectorModule直接导入到您的AppModule中。

import { ServiceInjectorModule } from './service-injector.module';

const impExpModules = [
  ...,
  ServiceInjectorModule,
  ...
];


@NgModule({
  imports: [impExpModules],
  exports: [impExpModules]
  })
export class MyLibModule {}

将MyLibModule导入到您的AppModule或最合适的位置。

现在在您的组件或类中,只需:

import { ServiceInjector } from '../modules/lib/service-injector.module';
import { MyService } from '../services/my.service';


export class MyCurrentClass {

  myService = ServiceInjector.get(MyService);

  ...
  
  myLocalFunction() {
      ...
      this.myService.myServiceFunction(...
  }

}