Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
382 views
in Technique[技术] by (71.8m points)

javascript - 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

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

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:

...
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:

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

What exactly is wrong with using window as useValue provider here? Is it a known pitfall? Does this limitation apply to all globals or all useValue providers?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I was having a similar problem but it was with a 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.

Basically, it boils done to using a factory method instead of a useValue in the providers. I'm not sure why it's a problem, but I do know that this approach solves the aot problem.

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:

...
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 };

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...