core icon indicating copy to clipboard operation
core copied to clipboard

ngx-translate in library DI error when using in HTTP_INTERCEPTOR

Open ullalaaron opened this issue 3 years ago • 2 comments

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?

ullalaaron avatar Jul 06 '21 09:07 ullalaaron

I found a workaround here : https://stackoverflow.com/questions/67152273/angular-circular-dependency-when-inject-translateservice-to-interceptor

yassinumer avatar Sep 26 '21 14:09 yassinumer

@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 { }

yksht avatar Apr 04 '22 09:04 yksht