简体   繁体   English

当用作 Angular 4 AoT 的 useValue 提供程序时,窗口未定义

[英]window is undefined when used as useValue provider with Angular 4 AoT

When Angular 4.0.2 application is compiled ahead-of-time, and the provider is defined as useValue当 Angular 4.0.2 应用程序被提前编译,并且 provider 被定义为useValue

import { OpaqueToken, Provider } from '@angular/core';

export const windowToken = new OpaqueToken('window');
export const windowProvider = { provide: windowToken, useValue: window };

and used like并使用像

@NgModule({ providers: [windowProvider], ... })
export class AppModule {}

it compiles ok but results in window being undefined when injected as它编译正常,但在注入时导致window undefined

constructor(@Inject(windowToken) window) {
   window.navigator...
}

The error is thrown on bootstrapping:引导时抛出错误:

TypeError: Cannot read property 'navigator' of undefined类型错误:无法读取未定义的属性“导航器”

On a closer look at auto-generated app.module.ngfactory.js it appears that it is indeed undefined :仔细查看自动生成的 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;
        }
        ...

When the same service is used as useFactory , everything is ok:当使用相同的服务作为useFactory ,一切正常:

export function windowFactory() {
  return window;
}
export const windowProvider = { provide: windowToken, useFactory: windowFactory };

What exactly is wrong with using window as useValue provider here?在这里使用window作为useValue提供者到底有什么问题? Is it a known pitfall?这是一个众所周知的陷阱吗? Does this limitation apply to all globals or all useValue providers?此限制是否适用于所有全局变量或所有useValue提供程序?

I was having a similar problem but it was with a SignalrWindow.我遇到了类似的问题,但它与 SignalrWindow 有关。 The concept and the error though was identical.虽然概念和错误是相同的。

I then found this article here ( https://blog.sstorie.com/integrating-angular-2-and-signalr-part-2-of-2/ ), and there were some comments at the bottom of the article that helped me solve the problem.然后我在这里找到了这篇文章( https://blog.sstorie.com/integrating-angular-2-and-signalr-part-2-of-2/ ),文章底部有一些评论帮助我解决问题。

Basically, it boils done to using a factory method instead of a useValue in the providers.基本上,它归结为在提供程序中使用工厂方法而不是 useValue。 I'm not sure why it's a problem, but I do know that this approach solves the aot problem.我不确定为什么会出现问题,但我知道这种方法解决了 aot 问题。

The steps to fix:修复步骤:

Create a function that is exported创建一个导出的函数

export function windowFactory(): any {
    return window;
}

Then in the core module, in @NgModule in the providers you can do this:然后在核心模块中,在提供程序中的@NgModule中,您可以执行以下操作:

...
providers: [
    { provide: SignalrWindow, useFactory: windowFactory }
  ]
...

Basically, you can rename the methods however you like (so, in your example it would be:)基本上,您可以根据自己的喜好重命名方法(因此,在您的示例中,它将是:)

export const windowProvider = { provide: windowToken, useFactory: windowFactory };

During AoT compilation, angular CLI statically analyses code too generate ngmodule.factory file.在 AoT 编译期间,angular CLI 也会静态分析代码,生成 ngmodule.factory 文件。 It sees "useValue" and check if static value is available and puts it into ngmodule.factory.它看到“useValue”并检查静态值是否可用并将其放入 ngmodule.factory。 During compile time, this value is not available, so it leaves that provider value and hence, it is returned as "undefined" when injected into constuctor.在编译期间,此值不可用,因此它会保留该提供程序值,因此,当注入构造函数时,它会以“未定义”的形式返回。

However, "useFactory" is provided for very same purpose where you don't know your value until runtime.但是,提供“useFactory”的目的非常相同,直到运行时您才知道您的价值。

Due to this, useValue is not working in your scenario, but "useFactory" will work.因此,useValue 在您的场景中不起作用,但“useFactory”将起作用。

Bottom line: When AOT compilation, Use "useValue" only if you have static value like constant string or number.底线:在 AOT 编译时,仅当您具有常量字符串或数字等静态值时才使用“useValue”。 Else use "useFactory" to return run-time calculated object/values.否则使用“useFactory”返回运行时计算的对象/值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM