В моем приложении мне нужно использовать ng-intercomhttps://github.com/CaliStyle/ng-intercom, который требует, чтобы ключ конфигурации был установлен в методе forRoot().
Ключ конфигурации загружается из вызова API, выполненного в main.ts. Конфигурация загружается из API, затем устанавливается на APP_CONFIG в AppConfigService, а затем приложение загружается.
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));
}
app-config.service.ts
import { Injectable } from '@angular/core';
export let APP_CONFIG: any = {};
@Injectable()
export class AppConfigService {
constructor() {}
public set(config) {
APP_CONFIG = Object.assign(config);
}
}
В AppModule я импортирую APP_CONFIG и использую ключ из конфигурации в forRoot()IntercomModule:
app.module.ts
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"
}
Проблема: при инициализации IntercomModule ключ конфигурации не определен APP_CONFIG.intercomKey, потому что конфигурация еще не была получена из API.
Как мне убедиться, что конфигурация доступна при инициализации модулей? Любые идеи?
Раньше я пытался вызвать функцию в методе forRoot(), но при компиляции приложения с AOT получал ошибку Function calls are not supported in decorators.
См. Также stackblitz: https://stackblitz.com/edit/angular6-intercom-issue
Спасибо, попробую. Я использовал XMLHttpRequest для поддержки IE11.
И похоже, что HttpClient нельзя использовать в main.ts stackoverflow.com/questions/46681396/…
Так как вам придется использовать XMLHttpRequest, здесь - хороший пример того, как работать с async/await и им.
Использование обещаний, похоже, не решает мою проблему. Кажется, что Angular создает AppModule (строка 10) перед тем, как выполнить код, выполняющий запрос (строка 36). См. stackblitz.com/edit/…
Вы забыли использовать async/await. См. stackblitz.com/edit/angular6-intercom-issue-mmcjsj
Думаю, я понимаю, что здесь происходит. Похоже, что AppModule загружается до того, как main.ts выполняет свои функции.
Точно. Вы знаете, как этого избежать?





Проблема в том, что код в app.module.ts выполняется, как только вы импортируете его в свой main.ts. Вы должны динамически импортировать его для достижения своей цели. Я обновил ваш пример на Stackblitz, чтобы показать решение.
Однако вам, возможно, придется проверить, как TypeScript передает динамический импорт. Я не уверен, возможно ли в настоящее время ориентироваться на версию ES, которая широко поддерживается. См. Также документацию TypeScript по теме здесь.
Если есть возможность запросить и кэшировать конфигурацию приложения на сервере, это, на мой взгляд, было бы более чистым решением.
Спасибо, мне пришлось обновить свой tsconfig.json с помощью "module": "esNext" и "angularCompilerOptions": { "entryModule" : "./app/app.module#AppModule" }, чтобы избежать ошибок при компиляции. Теперь он работает при обслуживании в режиме разработки, но когда я компилирую для prod с AOT, я получаю следующую ошибку: «Отклонение необработанного обещания: метаданные NgModule для 'e' не найдены»
У меня была аналогичная проблема, и ответ @realhans также сломал AOT для меня.
Упомянутое решение здесь решает проблему, пока AOT продолжает работать.
Вы можете попробовать использовать
async/await. Здесь - хороший пример того, как его использовать. Это должно помочь. Также рассмотрите возможность использования AngularHttpClientвместоXMLHttpRequest.HttpClientпревратит ваш запрос в обещания, что упростит работу сasync/await. Вы можете посмотреть справочник здесь.