Reputation: 13997
I have a circular dependency (at run-time!) problem, which I don't see how to resolve.
I have registered an APP_INITIALIZER load function, which loads a config.json file. This config file contains among others the LogLevel
for NGXLogger
.
The config file is loaded through angular's HttpClient
.
Besides that, I have registered an HttpInterceptor
, which uses the NGXLogger
.
It seems that angular tries to resolve everything in this order:
APP_INITIALIZER
, so run this function firsthttp
call, so first run through the interceptorHttpInterceptor
=> NGXLogger
NGXLogger
=> based on the configuration file in APP_INITIALIZER
How can I resolve this circular dependencies? Is there a way to completely skip the interceptor on the APP_INITIALIZER
http call?
CoreModule.ts:
export function appConfigFactory(configService: AppConfigService) {
return () => configService.load();
}
export function loggerConfigFactory(configService: AppConfigService): {
return () => {
level: (NgxLoggerLevel as any)[configService.config.logLevel] || NgxLoggerLevel.ERROR,
};
}
@NgModule({
...
providers: [{
provide: APP_INITIALIZER,
useFactory: appConfigFactory,
deps: [AppConfigService],
multi: true
}, {
provide: NgxLoggerConfig,
useFactory: loggerConfigFactory,
deps: [AppConfigService]
}]
})
export class CoreModule {}
AppConfigService.ts:
export class AppConfigService {
constructor(private http: HttpClient) {}
load() {
return this.http
.get<AppConfig>(`/assets/configuration/${environment.configFile}`)
.pipe(
tap((config: any) => {
this.config = config;
})
)
.toPromise();
}
}
FakeBackendInterceptor:
@Injectable()
export class FakeBackendInterceptor implements HttpInterceptor {
constructor(private configService: AppConfigService, private logger: NGXLogger) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// config is undefined here the first time
if (!this.configService.config || !this.configService.config.mock === 'true') {
return next.handle(request);
}
this.logger.info('Intercepting request with mock');
// do things
...
return next.handle(request);
}
}
Upvotes: 2
Views: 1015
Reputation: 18381
You can use HttpBackend
to skip the interceptor in the config service
constructor(
private http: HttpClient,
private httpBackend: HttpBackend) { }
And in the load method
const httpClient = new HttpClient(this.httpBackend);
httpClient.get<AppConfig>(`/assets/configuration/${environment.configFile}`)
.pipe(
tap((config: any) => {
this.config = config;
})
)
.toPromise();
Upvotes: 4