我在使用Angular 4时遇到了一些自举问题。
我有一个配置文件(json),该文件是在我的应用程序启动时从服务器加载的(请参见here)。到目前为止,该方法有效。
现在,我有一个dependency,它要求在forRoot方法中传递配置值。实现看起来像这样:
static forRoot(config: AppInsightsConfig): ModuleWithProviders {
return {
ngModule: ApplicationInsightsModule,
providers: [
{ provide: AppInsightsConfig, useValue: config }
]
};
}
我的想法是在没有forRoot()的情况下导入模块,但要在从服务器加载配置后提供AppInsightsConfig。
@NgModule({
bootstrap: sharedConfig.bootstrap,
declarations: [...sharedConfig.declarations],
imports: [
BrowserModule,
FormsModule,
HttpModule,
ApplicationInsightsModule,
...sharedConfig.imports
],
providers: [
{ provide: 'ORIGIN_URL', useValue: location.origin },
{ provide:
APP_INITIALIZER,
useFactory: (configService: ConfigService) => () => configService.load(),
deps: [ConfigService], multi: true
},
{ provide:
AppInsightsConfig,
useFactory: (configService: ConfigService) => {
// outputs undefined, expected it to have the config
console.log(configService.config);
return { instrumentationKey: 'key from config' }
},
// My idea was, if I add APP_INITIALIZER as dependency,
// the config would have been loaded, but this isn't the case.
deps: [APP_INITIALIZER, ConfigService]
},
AppInsightsService
]
})
加载配置后,如何提供AppInsightsConfig或其他服务?
最佳答案
最后,我想出了以下解决方案:
这是我的应用程序模块现在的样子:
import { Resolve, Router } from '@angular/router';
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { sharedConfig } from './app.module.shared';
import { SiteControlModule } from './site-control/site-control.module';
import { SiteControlComponent } from './site-control/site-control.component';
import { AuthModule } from './auth/auth.module';
import { ConfigService } from './core/config/config.service';
import { ApplicationInsightsModule } from './application-insights/application-insights.module';
import { ApplicationInsightsService } from './application-insights/application-insights.service';
import { CoreModule } from './core/core.module';
let initializeConfig = (aiService: ApplicationInsightsService, configService: ConfigService) => () => {
let loadConfigPromise = configService.load();
loadConfigPromise.then(() => {
aiService.config = configService.config.applicationInsights;
aiService.init();
});
return loadConfigPromise;
};
@NgModule({
bootstrap: sharedConfig.bootstrap,
declarations: [...sharedConfig.declarations],
imports: [
BrowserModule,
FormsModule,
HttpModule,
AuthModule,
...sharedConfig.imports,
CoreModule.forRoot(),
ApplicationInsightsModule.forRoot(),
SiteControlModule
],
providers: [
{ provide: 'ORIGIN_URL', useValue: location.origin },
{ provide:
APP_INITIALIZER,
useFactory: initializeConfig,
deps: [ ApplicationInsightsService, ConfigService ],
multi: true
}
]
})
export class AppModule {
}
config.service.ts
import { Injectable } from '@angular/core';
import { Headers, RequestOptions, Http, Response} from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/toPromise';
import { Config } from './models/config.model';
@Injectable()
export class ConfigService {
config : Config;
constructor(private http: Http) {
console.log('constructing config service');
}
public load(): Promise<void> {
let headers = new Headers({ 'Content-Type': 'application/json' });
let url = 'environment.json';
let promise = this.http.get(url, { headers })
.toPromise()
.then(configs => {
console.log('environment loaded');
this.config = configs.json() as Config;
})
.catch(err => {
console.log(err);
});
return promise;
}
}
application-insights.service.ts的更改部分
import { Injectable, Optional, Injector } from '@angular/core';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';
import { AppInsights } from 'applicationinsights-js';
import 'rxjs/add/operator/filter';
import IAppInsights = Microsoft.ApplicationInsights.IAppInsights;
import { ApplicationInsightsConfig } from '../core/config/models/application-insights.model';
@Injectable()
export class ApplicationInsightsService implements IAppInsights {
context: Microsoft.ApplicationInsights.ITelemetryContext;
queue: Array<() => void>;
config: Microsoft.ApplicationInsights.IConfig;
constructor(@Optional() _config: ApplicationInsightsConfig, private injector: Injector) {
this.config = _config;
}
private get router(): Router {
return this.injector.get(Router);
}
...
application-insights.module.ts
import { NgModule, ModuleWithProviders, Optional, SkipSelf } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ApplicationInsightsService} from './application-insights.service';
export * from './application-insights.service';
@NgModule({
imports: [ CommonModule ],
declarations: [],
exports: [],
providers: []
})
export class ApplicationInsightsModule {
constructor(@Optional() @SkipSelf() parentModule: ApplicationInsightsModule) {
if (parentModule) {
throw new Error(
'ApplicationInsightsModule is already loaded. Import it in the AppModule only');
}
}
static forRoot(): ModuleWithProviders {
return {
ngModule: ApplicationInsightsModule,
providers: [ ApplicationInsightsService ]
};
}
}
关于angular - 在APP_INITIALIZE之后初始化其他提供程序,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44715578/