如何在 Angular 加载其模块之前获取异步数据
How to get asynchronous data before Angular loads its modules
我正在尝试将变量注入 Angular 模块的 forRoot({[...]})
方法。
我是通过异步的方式获取到这个变量的,所以我尝试在之前bootstrapAngular获取它。 (来自cordova.js)
问题:
似乎 Angular 在被 bootstrapped 之前导入模块(并调用 '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,而不是一个函数...
您可以使用 APP_INITIALIZER 提供将在模块导入之后但在 Bootstrap 之前执行的工厂。因此,您可以将 apiKey 设置为任何值并在工厂中覆盖它:创建一个函数来获取所需的数据并将 apiKey 设置到 LAZY_MAPS_API_CONFIG
对象中。
一旦所有 APP_INITIALIZERS
都已解决,应用程序 bootstrap 将继续。
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 { }
用于将称为异步的值填充到 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 {
}
我正在尝试将变量注入 Angular 模块的 forRoot({[...]})
方法。
我是通过异步的方式获取到这个变量的,所以我尝试在之前bootstrapAngular获取它。 (来自cordova.js)
问题:
似乎 Angular 在被 bootstrapped 之前导入模块(并调用 '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,而不是一个函数...
您可以使用 APP_INITIALIZER 提供将在模块导入之后但在 Bootstrap 之前执行的工厂。因此,您可以将 apiKey 设置为任何值并在工厂中覆盖它:创建一个函数来获取所需的数据并将 apiKey 设置到 LAZY_MAPS_API_CONFIG
对象中。
一旦所有 APP_INITIALIZERS
都已解决,应用程序 bootstrap 将继续。
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 { }
用于将称为异步的值填充到 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 {
}