core
core copied to clipboard
ngx-translate in library DI error when using in HTTP_INTERCEPTOR
I have a angular library where I created a LanguageModule
defined as follows
@NgModule({
imports: [
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: (createTranslateLoader),
deps: [HttpClient]
},
})
],
exports: [TranslateModule]
})
export class LanguageModule {
public constructor(translateSvc: TranslateService, http: HttpClient) {
translateSvc.onLangChange
.pipe(
switchMap((currentLang: LangChangeEvent) => zip(
of(currentLang),
http.get(`assets/i18n/${currentLang.lang}.json`),
))
).subscribe(([currentLang, localizations, syncfusionLocalization]) => {
translateSvc.setTranslation(translateSvc.currentLang, localizations, true);
setCulture(currentLang.lang);
});
translateSvc.use(translateSvc.getDefaultLang());
}
}
This allows me to merge library and app localization files.
Inside my app I import the LanguageModule
in the main app.module.ts
, where I also import my CoreModule
, defined as follows:
@NgModule({
imports: [
CommonModule,
HttpClientModule,
BrowserAnimationsModule,
...
],
declarations: [],
providers: [
....
// Http interceptors
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}
]
})
export class CoreModule {
public constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
if (parentModule) {
throw new Error('CoreModule has already been loaded. Import CoreModule in the AppModule only.');
}
}
}
In the AuthInterceptor
, if I inject the TranslateService
I get the following error:
Circular dependency in DI detected for InjectionToken HTTP_INTERCEPTORS.
What am I missing?
I found a workaround here : https://stackoverflow.com/questions/67152273/angular-circular-dependency-when-inject-translateservice-to-interceptor
@ullalaaron
Problem exists because TranslateLoader uses HttpClient as dependency but this client could not be initialized before HTTP_INTERCEPTORS. So you just can not provide class which injects HttpClient (or other services which injects it) as HTTP_INTERCEPTORS provider.
Here is a good solution to use HttpBackend for TranslateLoader. There is one more good point: requests to the localization files won't pass through the interceptors chain.
export class TranslateHttpLoader implements TranslateLoader {
constructor(
private httpHandler: HttpBackend,
public prefix: string,
public suffix: string,
) { }
getTranslation(lang: string): Observable<unknown> {
const httpRequest = new HttpRequest('GET', `${this.prefix}${lang}${this.suffix}`);
return this.httpHandler.handle(httpRequest)
.pipe(
filter((httpEvent: HttpEvent<any>) => httpEvent instanceof HttpResponse),
map((httpResponse: HttpResponse<any>) => httpResponse.body),
);
}
}
export function translateLoaderFactory(httpHandler: HttpBackend,): TranslateLoader {
return new TranslateHttpLoader(httpHandler, './assets/i18n/', '.json');
}
export const TRANSLATE_MODULE_CONFIG: TranslateModuleConfig = {
loader: {
provide: TranslateLoader,
useFactory: translateLoaderFactory,
deps: [
HttpBackend,
],
},
//...
};
// use TRANSLATE_MODULE_CONFIG
@NgModule({
imports: [
//...
TranslateModule.forRoot(TRANSLATE_MODULE_CONFIG),
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true,
},
],
//...
})
export class AppModule { }