将 TranslateService 注入拦截器时的 Angular 循环依赖

luk*_*ear 8 cyclic-dependency ngx-translate angular

我在将依赖项注入拦截器时遇到问题。我想将 TranslateService 注入 HttpErrorInterceptor,但出现循环依赖错误。当我删除 TranslateService 注入时,一切正常。

\n

我已在 app.module.ts 中声明了拦截器。\n我的应用程序模块如下所示:

\n
@NgModule({\n declarations: [\n   AppComponent\n ],\n imports: [\n   BrowserModule,\n   BrowserAnimationsModule,\n   CoreModule,\n   HttpClientModule,\n   TranslateModule.forRoot({\n   loader: {\n      provide: TranslateLoader,\n      useFactory: HttpLoaderFactory,\n      deps: [HttpClient],\n   },\n   defaultLanguage: \'pl-pl\'\n }),\n   AppRoutingModule,\n   RouterModule,\n   FormsModule,\n   ReactiveFormsModule,\n   ToastrModule.forRoot()\n ],\n providers: [\n   {\n     provide: HTTP_INTERCEPTORS,\n     useClass: JwtInterceptor,\n     multi: true\n   },\n   {\n     provide: HTTP_INTERCEPTORS,\n     useClass: HttpErrorInterceptor,\n     multi: true,\n     deps: [TranslateService, ToastrService]\n   }\n ],\n bootstrap: [AppComponent]\n})\nexport class AppModule { }\n
Run Code Online (Sandbox Code Playgroud)\n

在 AppModule 中,我导入了 CoreModule,其中有一个包含拦截器的文件夹,我的 CoreModule 如下所示:

\n
@NgModule({\n  declarations: [],\n  imports: [\n    CommonModule\n  ],\n  providers: [\n    CookieService,\n    NoAuthGuard,\n    AuthGuard\n  ]\n})\nexport class CoreModule { }\n\n
Run Code Online (Sandbox Code Playgroud)\n

我将登录页面放在AuthModule中,如下所示:

\n
@NgModule({\n  declarations: [LoginComponent, AuthComponent, ForgotPasswordComponent],\n  imports: [\n    CommonModule,\n    AuthRoutingModule,\n    RouterModule,\n    SharedModule\n  ],\n  providers: [\n    AuthService\n  ]\n})\nexport class AuthModule { }\n
Run Code Online (Sandbox Code Playgroud)\n

在 Authmodule 中,我导入了 SharedModule,其中导出了 TranslateModule。\nSharedModule 如下所示:

\n
@NgModule({\n  declarations: [],\n  imports: [\n    CommonModule,\n    HttpClientModule,\n    ReactiveFormsModule\n  ],\n  exports: [\n    TranslateModule,\n    ReactiveFormsModule\n  ]\n})\nexport class SharedModule { }\n
Run Code Online (Sandbox Code Playgroud)\n

我无法找出为什么登录页面上出现循环依赖错误。

\n

我的假设是,我已将 CoreModule 导入到 AppModule 中,在其中保留拦截器、防护程序,并且我有 SharedModule,它为所有功能模块提供临时功能,并且我想在那里保留例如通用组件。

\n

B\xc5\x82\xc4\x85d,jaki dostaj\xc4\x99 到:

\n
core.js:6162 ERROR Error: NG0200: Circular dependency in DI detected for InjectionToken HTTP_INTERCEPTORS. Find more at https://angular.io/errors/NG0200\n    at throwCyclicDependencyError (core.js:216)\n    at R3Injector.hydrate (core.js:11381)\n    at R3Injector.get (core.js:11205)\n    at HttpInterceptingHandler.handle (http.js:1978)\n    at MergeMapSubscriber.project (http.js:1114)\n    at MergeMapSubscriber._tryNext (mergeMap.js:44)\n    at MergeMapSubscriber._next (mergeMap.js:34)\n    at MergeMapSubscriber.next (Subscriber.js:49)\n    at Observable._subscribe (subscribeToArray.js:3)\n    at Observable._trySubscribe (Observable.js:42)\n
Run Code Online (Sandbox Code Playgroud)\n

Ale*_*esD 14

您遇到的问题是,对于您的初始化,您TranslateModule依赖于这HttpClient意味着HttpClientModule需要首先初始化。这会导致您的初始化,HttpErrorInterceptor因为拦截器是通过HttpClientModule初始化来初始化的。这会导致循环依赖,因为您的拦截器需要TranslateService. 您可以通过将注入器注入到您的注入器中HttpErrorInterceptor,然后TranslateService在需要时直接从注入器请求来解决此问题。这样可以防止对初始初始化的循环依赖。

由于您没有为拦截器提供代码,因此这里是使用此方法的示例拦截器。

@Injectable()
export class HttpErrorInterceptor implements HttpInterceptor {
  constructor(private readonly injector: Injector) {}

  public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    try {
      const translateService = this.injector.get(TranslateService)
      // log using translate service
    } catch {
      // log without translation translation service is not yet available
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

您仍然需要处理获取翻译服务失败的情况,因为加载翻译时可能会出现错误。


Aar*_*lal 11

根据这个GitHub 问题,一些人(包括我自己)能够通过删除defaultLanguagein来解决这个问题TranslateModule.forRoot()

我已经实现了我的 LanguageModule 如下:

@NgModule({
  imports: [
    HttpClientModule,
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: (createTranslateLoader),
        deps: [HttpClient]
      },
      isolate: true
    })
  ],
  providers: [
    TranslateService
  ]
})
export class LanguageModule {
  public constructor(translateSvc: TranslateService, http: HttpClient) {
    translateSvc.onLangChange
      .pipe(
        switchMap((currentLang: LangChangeEvent) => zip(
          of(currentLang),
          http.get(`path/to/i18n/${currentLang.lang}.json`)
        ))
      ).subscribe(([currentLang, localizations]) => {
        translateSvc.setTranslation(translateSvc.currentLang, localizations, true);
      });

    translateSvc.use(translateSvc.getDefaultLang());
  }
Run Code Online (Sandbox Code Playgroud)

然后将其导入到我的CoreModule

@NgModule({
    imports: [
      CommonModule,
      HttpClientModule,
      BrowserAnimationsModule,
      LanguageModule,
      ...
    ],
    exports: [],
    declarations: [],
    providers: [
      ...
      {
        provide: HTTP_INTERCEPTORS,
        useClass: AuthInterceptor,
        multi: true
      }
    ]
  })
  export class CoreModule {
    public constructor(@Optional() @SkipSelf() parentModule: CoreModule, private translateSvc: TranslateService) {
      this.translateSvc.use(environment.defaultLang)
    }
}
Run Code Online (Sandbox Code Playgroud)