提前编译Angular 4.0.2应用程序,并将提供程序定义为useValue
import { OpaqueToken, Provider } from '@angular/core';
export const windowToken = new OpaqueToken('window');
export const windowProvider = { provide: windowToken, useValue: window };
并使用
@NgModule({ providers: [windowProvider], ... })
export class AppModule {}
它编译正常,但当注入为
时导致window
为undefined
constructor(@Inject(windowToken) window) {
window.navigator...
}
引导时抛出错误:
TypeError:无法读取未定义的属性“navigator”
仔细查看自动生成的app.module.ngfactory.js,看来它确实是undefined
:
...
import * as import39 from './window';
var AppModuleInjector = (function (_super) {
...
AppModuleInjector.prototype.createInternal = function () {
...
this._windowToken_26 = undefined;
this._SomeService_27 = new import16.SomeService(this._windowToken_26);
}
AppModuleInjector.prototype.getInternal = function (token, notFoundResult) {
...
if ((token === import39.windowToken)) {
return this._windowToken_26;
}
...
当同一服务用作useFactory
时,一切正常:
export function windowFactory() {
return window;
}
export const windowProvider = { provide: windowToken, useFactory: windowFactory };
在这里使用window
useValue
提供商有什么问题?这是一个众所周知的陷阱吗?此限制是否适用于所有全局或所有useValue
提供程序?
答案 0 :(得分:2)
我遇到了类似的问题,但是有一个SignalrWindow。这个概念和错误虽然相同。
然后我在这里找到了这篇文章(https://blog.sstorie.com/integrating-angular-2-and-signalr-part-2-of-2/),文章底部有一些评论帮我解决了这个问题。
基本上,它可以在提供程序中使用工厂方法而不是useValue。我不确定为什么这是一个问题,但我知道这种方法解决了这个问题。
要修复的步骤:
创建导出的函数
export function windowFactory(): any {
return window;
}
然后在核心模块中,在提供程序的@NgModule
中,您可以执行此操作:
...
providers: [
{ provide: SignalrWindow, useFactory: windowFactory }
]
...
基本上,您可以根据需要重命名方法(因此,在您的示例中,它将是:)
export const windowProvider = { provide: windowToken, useFactory: windowFactory };
答案 1 :(得分:1)
在AoT编译期间,angular CLI静态分析代码也生成ngmodule.factory文件。它看到“useValue”并检查静态值是否可用并将其放入ngmodule.factory。在编译期间,此值不可用,因此它将保留该提供程序值,因此,当将其注入constuctor时,它将返回为“undefined”。
但是,“useFactory”提供的目的非常相同,直到运行时才知道你的值。
因此,useValue在您的方案中不起作用,但“useFactory”将起作用。
底线:当AOT编译时,只有在具有常量字符串或数字的静态值时才使用“useValue”。否则使用“useFactory”返回运行时计算的对象/值。