簡體   English   中英

Angular 向攔截器注入 TranslateService 時的循環依賴

[英]Angular Circular dependency when inject TranslateService to interceptor

我在將依賴項注入攔截器時遇到問題。 我想將 TranslateService 注入 HttpErrorInterceptor,但出現循環依賴錯誤。 當我刪除 TranslateService 注入時,一切正常。

我已經在我的 app.module.ts 中聲明了攔截器。 我的應用模塊如下所示:

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

在 AppModule 中,我導入了 CoreModule,其中有一個包含攔截器的文件夾,我的 CoreModule 如下所示:

@NgModule({
  declarations: [],
  imports: [
    CommonModule
  ],
  providers: [
    CookieService,
    NoAuthGuard,
    AuthGuard
  ]
})
export class CoreModule { }

我把登錄頁面放在AuthModule中,如下所示:

@NgModule({
  declarations: [LoginComponent, AuthComponent, ForgotPasswordComponent],
  imports: [
    CommonModule,
    AuthRoutingModule,
    RouterModule,
    SharedModule
  ],
  providers: [
    AuthService
  ]
})
export class AuthModule { }

在 Authmodule 中,我導入了 SharedModule,並在其中導出了 TranslateModule。 SharedModule 看起來像這樣:

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    HttpClientModule,
    ReactiveFormsModule
  ],
  exports: [
    TranslateModule,
    ReactiveFormsModule
  ]
})
export class SharedModule { }

我找不到登錄頁面上出現循環依賴錯誤的原因。

我的假設是我已經將 CoreModule 導入到 AppModule 中,在那里我保留了攔截器、守衛和 SharedModule,它對所有功能模塊進行了即興創作,並且我想在那里保留例如公共組件。

Błąd, jaki dostaję to:

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

您遇到的問題是,對於TranslateModule的初始化,您依賴於HttpClient ,這意味着需要首先初始化HttpClientModule 這會導致您的HttpErrorInterceptor初始化,因為攔截器是使用HttpClientModule初始化進行初始化的。 這會導致循環依賴,因為您的攔截器需要TranslateService 您可以通過在HttpErrorInterceptor中注入Injector來解決此問題,然后在需要時直接從注入器請求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
    }
  }
}

您仍然需要處理獲取翻譯服務失敗的情況,因為加載翻譯時可能會出錯。

根據這個GitHub 問題,包括我自己在內的一些人能夠通過刪除TranslateModule.forRoot()中的defaultLanguage來解決該問題

我已經實現了我的 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());
  }

然后將其導入我的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)
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM