Can't inject `Route` nor `ActivatedRouteSnapshot` into `HttpInterceptor`

2.9k views Asked by At

Simplified version of the code:

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
  constructor(
    private readonly router: Router,
    private readonly activatedRouteSnapshot: ActivatedRouteSnapshot,
    @Inject(AuthServiceFactory) private readonly authServiceFactory: ServiceFactoryBase<IAuthService>,
    @Inject(LoggingServiceFactory) private readonly loggingServiceFactory: ServiceFactoryBase<ILoggingService>) {
    console.log('router', router);
    console.log('activated-route-snapshot', activatedRouteSnapshot);
  }

None of that can be resolved. It fails with a standard message saying following:

StaticInjectorError(AppModule)[InjectionToken HTTP_INTERCEPTORS -> ActivatedRouteSnapshot]: StaticInjectorError(Platform: core)[InjectionToken HTTP_INTERCEPTORS -> ActivatedRouteSnapshot]: NullInjectorError: No provider for ActivatedRouteSnapshot!

..what is the correct way to import RouterModule into an application?

P.S. I got SharedModule rather than the AppModule to export all mine stuff but not Angular's:

@NgModule({
    declarations: any.concat(pipes),
    providers: any
        .concat(serviceFactories)
        .concat(guards)
        .concat(otherProviders)
        .concat([{
            provide: HTTP_INTERCEPTORS,
            useClass: JwtInterceptor,
            multi: true
        }]),
    exports: any.concat(pipes)
})
export class SharedModule {
    static forRoot(): ModuleWithProviders {
        return {
            ngModule: SharedModule,
            providers: any
                .concat(serviceFactories)
                .concat(guards)
                .concat(otherProviders)
        };
    }
}

The the AppModule:

@NgModule({
  declarations: appComponents.concat(auxComponents),
  imports: [
    // theirs
    BrowserModule,
    HttpClientModule,
    AppRoutingModule,

    // ours
    SharedModule,
    CoursesModule
  ],
  bootstrap: [
    AppComponent
  ]
})
export class AppModule { }
1

There are 1 answers

7
joh04667 On BEST ANSWER

When you're using a ClassProvider as you must do for an HttpInterceptor, Angular can't compile provider dependencies like it would for providers that are included in the module as tokens themselves. Basically, type tokens don't really exist at runtime, and Angular uses these tokens for dependency injection -- since a ClassProvider or a ValueProvider are evaluated at runtime, they don't get the proper DI treatment they deserve.

You'll just have to be a bit more declarative about it:

    {
        provide: HTTP_INTERCEPTORS,
        useClass: JwtInterceptor,
        deps: [Router, ActivatedRoute],
        multi: true
    }

The tokens in the deps array will be injected into the component on creation. One finicky thing here is that the deps have to be in the same order as they are in the constructor parameters.

Also, an ActivatedRouteSnapshot's provider is just ActivatedRoute.

You should be able to accomplish the same thing by using the @Inject() decorator, as you've done with the other providers -- Angular will walk up the dependency tree for the first match and inject it (though I'm not 100% certain on this).