1

I have AppModule snippet where I am injecting token handling interceptor

@NgModule({
 imports: [
   BrowserModule,
   HttpClientModule
 ],
 declarations: [AppComponent],
 providers: [
   AuthService,
   {
     provide: HTTP_INTERCEPTORS,
     useClass: BasicTokenInterceptor,
     multi: true
   }
 ],
 exports: [AppComponent],
 bootstrap: [AppComponent]
})
export class AppModule { }

My Interceptor

@Injectable()
export class BasicTokenInterceptor implements HttpInterceptor {

    constructor(private auth: AuthService) {}
...

Receiving Error

Uncaught Error: Provider parse errors:
Cannot instantiate cyclic dependency! InjectionToken_HTTP_INTERCEPTORS ("[ERROR ->]"): in NgModule AppModule in ./AppModule@-1:-1
    at NgModuleProviderAnalyzer.webpackJsonp.../../../compiler/@angular/compiler.es5.js.NgModuleProviderAnalyzer.parse (compiler.es5.js:11684)
    at NgModuleCompiler.webpackJsonp.../../../compiler/@angular/compiler.es5.js.NgModuleCompiler.compile (compiler.es5.js:18497)
    at JitCompiler.webpackJsonp.../../../compiler/@angular/compiler.es5.js.JitCompiler._compileModule (compiler.es5.js:26825)
    at compiler.es5.js:26770
    at Object.then (compiler.es5.js:1679)
    at JitCompiler.webpackJsonp.../../../compiler/@angular/compiler.es5.js.JitCompiler._compileModuleAndComponents (compiler.es5.js:26768)
    at JitCompiler.webpackJsonp.../../../compiler/@angular/compiler.es5.js.JitCompiler.compileModuleAsync (compiler.es5.js:26697)
    at PlatformRef_.webpackJsonp.../../../core/@angular/core.es5.js.PlatformRef_._bootstrapModuleWithZone (core.es5.js:4536)
    at PlatformRef_.webpackJsonp.../../../core/@angular/core.es5.js.PlatformRef_.bootstrapModule (core.es5.js:4522)
    at Object.../../../../../src/main.ts (main.ts:11)

If I do injection inside intercept:

@Injectable()
export class BasicTokenInterceptor implements HttpInterceptor {

    auth:AuthService;

    constructor(private _injector:Injector) {}

    addToken(req: HttpRequest<any>, token: string): HttpRequest<any> {

       return (req as HttpRequest<any>).clone({ setHeaders: { Authorization: token }});
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {

       this.auth = this._injector.get(AuthService);

       return next.handle(this.addToken(req, this.auth.getToken()) 
...

Then relative error:

ERROR TypeError: Cannot read property 'length' of null
    at HttpHeaders.webpackJsonp.../../../common/@angular/common/http.es5.js.HttpHeaders.applyUpdate (http.es5.js:481)
    at http.es5.js:440
    at Array.forEach (<anonymous>)
    at HttpHeaders.webpackJsonp.../../../common/@angular/common/http.es5.js.HttpHeaders.init (http.es5.js:440)
    at HttpHeaders.webpackJsonp.../../../common/@angular/common/http.es5.js.HttpHeaders.forEach (http.es5.js:519)
    at Observable._subscribe (http.es5.js:1628)
    at Observable.webpackJsonp.../../../../rxjs/Observable.js.Observable._trySubscribe (Observable.js:171)
    at Observable.webpackJsonp.../../../../rxjs/Observable.js.Observable.subscribe (Observable.js:159)
    at CatchOperator.webpackJsonp.../../../../rxjs/operator/catch.js.CatchOperator.call (catch.js:79)
    at Observable.webpackJsonp.../../../../rxjs/Observable.js.Observable.subscribe (Observable.js:156)

I tried solutions mentioned in Angular git Cyclic dependency error with HttpInterceptor #18224 But still no success.

Sumit Ramteke
  • 1,487
  • 1
  • 16
  • 39
  • Have you tried to inject your service only when intercept is called as mentioned in the issue you checked ? Do you have the same error if that's the case ? – Orodan May 02 '18 at 17:29
  • @Orodan can you point me of which user comment you are talking about? Coz my intercept will be called at every request. – Sumit Ramteke May 03 '18 at 05:10
  • I have checked out [StackOverflow Julio](https://stackoverflow.com/a/47797278/2443988) solution. But there even they used couple of flags in intercept function. Looking for cleaner way, as this is common issue. – Sumit Ramteke May 03 '18 at 05:12
  • 1
    The solution from @perusopersonale. It gets the required service in the intercept method instead of getting it on the constructor. – Orodan May 03 '18 at 09:36
  • yes that even is working. I am asking for cleaner or recommended way – Sumit Ramteke May 03 '18 at 10:47
  • Getting your service instance in your constructor through the injector is the recomanded way to solve a cyclic dependency problem, is it working ? I though you were just looking for a solution first – Orodan May 03 '18 at 12:00
  • When I do that, I receive another error for HttpHeader while authenticating. Please see my updated question – Sumit Ramteke May 03 '18 at 12:32

1 Answers1

1

You can inject the service manually via Injector, it will help to avoid such kind of errors:

/* Other imports */
import { Injectable, Injector } from '@angular/core';
import { AuthService } from 'path/to/auth.service';

@Injectable()
export class BasicTokenInterceptor implements HttpInterceptor {
  constructor(private _injector: Injector) {
    setTimeout(() => {
      const _authService = this._injector.get(AuthService);
      /* Or store it to class property, as you like */
      _authService.callMethod();
      /* ... */
    });
  }
/* ... */
}
P.S.
  • 15,970
  • 14
  • 62
  • 86
  • Yes this works, even in angular git issue, it is mentioned. But user `tarasbobak` mentioned its a hackable way. Also, if I set `setTimeout` then `intercept` function is getting called even though authservice is not available. – Sumit Ramteke May 03 '18 at 05:01