【问题标题】:How to get asynchronous data before Angular loads its modules如何在 Angular 加载其模块之前获取异步数据
【发布时间】:2019-04-13 04:44:56
【问题描述】:

我正在尝试将变量注入到 Angular 模块的 forRoot({[...]}) 方法中。

我以异步方式获得了这个变量,所以我尝试在 bootstrap Angular 之前获得它。 (来自cordova.js

问题:

似乎 Angular 在被引导之前导入了模块(并调用了“forRoot”方法)。

有没有办法做到这一点?

谢谢!


我尝试过的一个例子:

app.module.ts

import {NgModule} from '@angular/core';
import {AgmCoreModule} from '@agm/core';

@NgModule({
  imports: [
    AgmCoreModule.forRoot({
      apiKey: window['device'].platform, // value is 'null' instead of 'browser' or something else
      libraries: ['places']
    })
  ],
  // [...]
  bootstrap: [AppComponent]
})

export class AppModule {
}

src/main.ts

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

document.addEventListener('deviceready', () => {
  console.log(window['device'].platform); // log 'browser'
  platformBrowserDynamic().bootstrapModule(AppModule)
    .catch(err => console.log(err));
}, false);

/!\提示

我正在使用的库 (@agm/core) 期望字符串作为 apiKey,而不是函数...

【问题讨论】:

    标签: angular cordova module phonegap


    【解决方案1】:

    您可以使用APP_INITIALIZER 提供一个工厂,该工厂将在模块导入之后但在 Bootstrap 之前执行。因此,您可以将 apiKey 设置为任何值并在工厂中将其覆盖:创建一个函数来获取所需的数据并将 apiKey 设置为 LAZY_MAPS_API_CONFIG 对象。 解决所有APP_INITIALIZERS 后,应用程序引导程序将继续。

    import { NgModule, APP_INITIALIZER } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { HttpClientModule, HttpClient } from '@angular/common/http';
    import { AgmCoreModule, LAZY_MAPS_API_CONFIG, LazyMapsAPILoaderConfigLiteral } from '@agm/core';
    import { AppComponent } from './app.component';
    import { map } from 'rxjs/operators';
    
    export function agmConfigFactory(http: HttpClient, config: LazyMapsAPILoaderConfigLiteral) {
      return () => http.get<{mapsApiKey: string}>("url").pipe(
        map(response => {
            config.apiKey = response.mapsApiKey;
            return response;
        })
      ).toPromise();
    }
    
    @NgModule({
      imports:      [ BrowserModule, HttpClientModule, AgmCoreModule.forRoot({ apiKey: "initialKey"}) ],
      declarations: [ AppComponent ],
      providers: [ {
        provide: APP_INITIALIZER, 
        useFactory: agmConfigFactory, 
        deps: [HttpClient, LAZY_MAPS_API_CONFIG], 
        multi: true} 
        ],
      bootstrap:    [ AppComponent ]
    })
    export class AppModule { }
    

    【讨论】:

    • 谢谢,效果很好;我已经将 APP_INITIALIZERS 用于其他事情,但我认为它不适合这种情况 :)
    • 这个答案有点晚了,但我遇到了同样的问题(尽管使用不同的包)。这仅仅是因为它们暴露了LAZY_MAPS_API_CONFIG而起作用吗?我正在使用的包接受 forRoot() 中的一个对象,我想用来自 HTTP 查询的数据填充该对象。
    • 这对我很有帮助。当然,这有点像 hack,但是 Angular 和 Angular Google Maps 没有提供返回 LAZY_MAPS_API_CONFIG 的 promise/observable 的方法。请记住,您必须在 AgmCoreModule.forRoot({ apiKey: '' }) 中提供一个 apiKey,即使它最初是一个空字符串。
    • @JWess 您不需要提供密钥,只需提供配置对象即可。在 forRoot 中给 apiKey 一个值将覆盖您在 agmConfigFactory 方法中设置的内容。
    【解决方案2】:

    用于将称为异步的值填充到 forRoot() 的导入中。

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule, APP_INITIALIZER } from '@angular/core';
    import { FormsModule } from "@angular/forms";
    import { AppComponent } from './app.component';
    import { MqttModule, IMqttServiceOptions } from "ngx-mqtt";
    import { HttpClient, HttpClientModule } from '@angular/common/http';
    import { map } from 'rxjs/operators';
    
    export const MQTT_SERVICE_OPTIONS: IMqttServiceOptions = {
      url: ""
    }
    
    export function wssConfig(http: HttpClient) {
      return () => http.get<{ data: string }>("url").pipe(
        map(response => {
          MQTT_SERVICE_OPTIONS.url = response.data;
          return response;
        })
      ).toPromise();
    }
    
    @NgModule({
      declarations: [
        AppComponent,
      ],
      imports: [
        BrowserModule,
        FormsModule,
        HttpClientModule,
        MqttModule.forRoot(MQTT_SERVICE_OPTIONS)
      ],
      providers: [
        {
          provide: APP_INITIALIZER,
          useFactory: wssConfig,
          deps: [HttpClient],
          multi: true
        }
      ],
      bootstrap: [AppComponent]
    })
    export class AppModule {
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-10
      • 2017-05-13
      • 1970-01-01
      • 2020-02-20
      • 2019-11-14
      • 1970-01-01
      • 2016-08-02
      • 2020-11-18
      相关资源
      最近更新 更多