Cuando la aplicación Angular 4.0.2 se compila con anticipación y el proveedor se define como useValue
import { OpaqueToken, Provider } from '@angular/core'; export const windowToken = new OpaqueToken('window'); export const windowProvider = { provide: windowToken, useValue: window };y usado como
@NgModule({ providers: [windowProvider], ... }) export class AppModule {} compila bien, pero da como resultado que window no esté undefined cuando se inyecta como
constructor(@Inject(windowToken) window) { window.navigator... }El error se lanza en el arranque:
TypeError: no se puede leer la propiedad 'navegador' de indefinido
En una mirada más cercana a app.module.ngfactory.js generado automáticamente, parece que de hecho no está 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; } ... Cuando se usa el mismo servicio que useFactory , todo está bien:
export function windowFactory() { return window; } export const windowProvider = { provide: windowToken, useFactory: windowFactory }; ¿Qué es exactamente lo que está mal con el uso de la window como proveedor de useValue aquí? ¿Es una trampa conocida? ¿Esta limitación se aplica a todos los globales oa todos los proveedores de useValue ?
Estaba teniendo un problema similar pero fue con SignalrWindow. Sin embargo, el concepto y el error eran idénticos.
Luego encontré este artículo aquí ( https://blog.sstorie.com/integrating-angular-2-and-signalr-part-2-of-2/ ), y había algunos comentarios al final del artículo que ayudaron yo solucione el problema.
Básicamente, se trata de usar un método de fábrica en lugar de un valor de uso en los proveedores. No estoy seguro de por qué es un problema, pero sé que este enfoque resuelve el problema.
Los pasos para arreglar:
Crear una función que se exporte
export function windowFactory(): any { return window; } Luego, en el módulo central, en @NgModule en los proveedores, puede hacer esto:
... providers: [ { provide: SignalrWindow, useFactory: windowFactory } ] ...Básicamente, puede cambiar el nombre de los métodos como desee (entonces, en su ejemplo sería :)
export const windowProvider = { provide: windowToken, useFactory: windowFactory };Durante la compilación de AoT, la CLI angular analiza estáticamente el código y genera el archivo ngmodule.factory. Ve "useValue" y verifica si el valor estático está disponible y lo coloca en ngmodule.factory. Durante el tiempo de compilación, este valor no está disponible, por lo que deja ese valor de proveedor y, por lo tanto, se devuelve como "indefinido" cuando se inyecta en constuctor.
Sin embargo, "useFactory" se proporciona con el mismo propósito en el que no conoce su valor hasta el tiempo de ejecución.
Debido a esto, useValue no funciona en su escenario, pero "useFactory" funcionará.
En pocas palabras: cuando se compila AOT, use "useValue" solo si tiene un valor estático como una cadena o un número constante. De lo contrario, use "useFactory" para devolver valores/objetos calculados en tiempo de ejecución.