Angular6在模块forRoot()中使用获取的配置变量

Angular6在模块forRoot()中使用获取的配置变量,angular,angular-cli,Angular,Angular Cli,在我的应用程序中,我需要使用ng对讲机,这需要在forRoot()方法中设置一个配置键 配置键从API调用加载,在main.ts中完成。从API获取配置,然后在AppConfigService中设置为APP\u config,然后启动应用程序 main.ts const appConfigRequest = new XMLHttpRequest(); appConfigRequest.addEventListener('load', onAppConfigLoad); appConfigRequ

在我的应用程序中,我需要使用
ng对讲机
,这需要在
forRoot()方法中设置一个配置键

配置键从API调用加载,在
main.ts
中完成。从API获取配置,然后在
AppConfigService
中设置为
APP\u config
,然后启动应用程序

main.ts

const appConfigRequest = new XMLHttpRequest();
appConfigRequest.addEventListener('load', onAppConfigLoad);
appConfigRequest.open('GET', 'https://api.myjson.com/bins/lf0ns');
appConfigRequest.send();

// Callback executed when app config JSON file has been loaded.
function onAppConfigLoad() {
    const config = JSON.parse(this.responseText);
    initConfig(config);
}

// Sets fetched config to AppConfigService constant APP_CONFIG and calls bootstrap()
function initConfig(config) {
    const injector = ReflectiveInjector.resolveAndCreate([AppConfigService]);
    const configService = injector.get(AppConfigService);
    configService.set(config);

    bootstrap();
}

function bootstrap() {
  platformBrowserDynamic().bootstrapModule(AppModule).then().catch(err => console.error(err));
}
import { Injectable } from '@angular/core';

export let APP_CONFIG: any = {};

@Injectable()
export class AppConfigService {

    constructor() {}

    public set(config) {
        APP_CONFIG = Object.assign(config);
    }
}
import { NgModule, InjectionToken, Inject, APP_INITIALIZER } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

import { APP_CONFIG } from './../shared/services/app-config.service';
import { IntercomModule } from 'ng-intercom';

@NgModule({
  imports:      [ 
    BrowserModule, 
    FormsModule,
    IntercomModule.forRoot({
        appId : APP_CONFIG.intercomKey,
        updateOnRouterChange: false
    })
  ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})

export class AppModule { }
app config.service.ts

const appConfigRequest = new XMLHttpRequest();
appConfigRequest.addEventListener('load', onAppConfigLoad);
appConfigRequest.open('GET', 'https://api.myjson.com/bins/lf0ns');
appConfigRequest.send();

// Callback executed when app config JSON file has been loaded.
function onAppConfigLoad() {
    const config = JSON.parse(this.responseText);
    initConfig(config);
}

// Sets fetched config to AppConfigService constant APP_CONFIG and calls bootstrap()
function initConfig(config) {
    const injector = ReflectiveInjector.resolveAndCreate([AppConfigService]);
    const configService = injector.get(AppConfigService);
    configService.set(config);

    bootstrap();
}

function bootstrap() {
  platformBrowserDynamic().bootstrapModule(AppModule).then().catch(err => console.error(err));
}
import { Injectable } from '@angular/core';

export let APP_CONFIG: any = {};

@Injectable()
export class AppConfigService {

    constructor() {}

    public set(config) {
        APP_CONFIG = Object.assign(config);
    }
}
import { NgModule, InjectionToken, Inject, APP_INITIALIZER } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

import { APP_CONFIG } from './../shared/services/app-config.service';
import { IntercomModule } from 'ng-intercom';

@NgModule({
  imports:      [ 
    BrowserModule, 
    FormsModule,
    IntercomModule.forRoot({
        appId : APP_CONFIG.intercomKey,
        updateOnRouterChange: false
    })
  ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})

export class AppModule { }
AppModule
中,我导入
APP\u配置
,并使用
内部通信模块的
forRoot()
配置中的键:

应用程序模块.ts

const appConfigRequest = new XMLHttpRequest();
appConfigRequest.addEventListener('load', onAppConfigLoad);
appConfigRequest.open('GET', 'https://api.myjson.com/bins/lf0ns');
appConfigRequest.send();

// Callback executed when app config JSON file has been loaded.
function onAppConfigLoad() {
    const config = JSON.parse(this.responseText);
    initConfig(config);
}

// Sets fetched config to AppConfigService constant APP_CONFIG and calls bootstrap()
function initConfig(config) {
    const injector = ReflectiveInjector.resolveAndCreate([AppConfigService]);
    const configService = injector.get(AppConfigService);
    configService.set(config);

    bootstrap();
}

function bootstrap() {
  platformBrowserDynamic().bootstrapModule(AppModule).then().catch(err => console.error(err));
}
import { Injectable } from '@angular/core';

export let APP_CONFIG: any = {};

@Injectable()
export class AppConfigService {

    constructor() {}

    public set(config) {
        APP_CONFIG = Object.assign(config);
    }
}
import { NgModule, InjectionToken, Inject, APP_INITIALIZER } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

import { APP_CONFIG } from './../shared/services/app-config.service';
import { IntercomModule } from 'ng-intercom';

@NgModule({
  imports:      [ 
    BrowserModule, 
    FormsModule,
    IntercomModule.forRoot({
        appId : APP_CONFIG.intercomKey,
        updateOnRouterChange: false
    })
  ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})

export class AppModule { }
配置示例:

{
  "production": true,
  "envName": "staging",
  "apiBaseURL": "//api.staging.site.com/v1/",
  "intercomKey": "qz0b98qo"
}
问题:内部通信模块初始化时,配置键未定义
APP\u config.intercommkey
,因为尚未从API获取配置

如何确保模块初始化时配置可用?有什么想法吗

我以前尝试过在
forRoot()
方法中调用函数,但在使用AOT编译应用程序时遇到错误
装饰程序中不支持函数调用


另请参见stackblitz:

问题在于,app.module.ts中的代码在您将其导入main.ts时会立即执行。您必须动态导入它以实现您的目标。我更新了您的应用程序以显示解决方案

不过,您可能需要检查TypeScript是如何传输动态导入的。我不确定,目前是否有可能针对广泛支持的ES版本。另请参见主题中的TypeScript文档


如果可以请求并缓存服务器上的应用程序配置,我认为这将是一个更干净的解决方案。

我也遇到了类似的问题,@realhans的回答也破坏了我的AOT


上述解决方案在AOT继续工作时解决了问题。

您可以尝试使用
async/await
。是如何使用它的一个很好的例子。这应该能奏效。还可以考虑使用角的<代码> HTTPcli客< /代码>而不是<代码> XMLHttpRequest < /代码>。
HttpClient
将把您的请求包装成承诺,使使用
async/await
变得容易。你可以看看导游。谢谢,我会试试的。我使用了
XMLHttpRequest
来支持IE11。而且似乎HttpClient不能在main.ts中使用,因此,既然您必须使用
XMLHttpRequest
就可以很好地说明如何使用
async/wait
和它。使用承诺似乎不能解决我的问题。Angular似乎在点击执行请求的代码(第36行)之前创建了AppModule(第10行)。谢谢,我必须用
“模块”:“esNext”
“angularcomileroptions”:{“entryModule”:“/app/app.module#AppModule”}
更新我的
tsconfig.json
,以避免编译时出现错误。它现在在dev模式下工作,但是当我使用AOT为prod编译时,我得到了以下错误:“未处理的承诺拒绝:找不到'e'的NgModule元数据”