1

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 { }
Zazaeil
  • 3,900
  • 2
  • 14
  • 31

1 Answers1

2

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).

joh04667
  • 7,159
  • 27
  • 34
  • It still expects appropriate declaration: `ERROR Error: StaticInjectorError(AppModule)[InjectionToken HTTP_INTERCEPTORS -> ActivatedRouteSnapshot]: StaticInjectorError(Platform: core)[InjectionToken HTTP_INTERCEPTORS -> ActivatedRouteSnapshot]: NullInjectorError: No provider for ActivatedRouteSnapshot!`. – Zazaeil Oct 02 '18 at 20:54
  • Oh, whoops. The provider for an `ActivatedRouteSnapshot` is actually just called `ActivatedRoute`. – joh04667 Oct 02 '18 at 21:01
  • Seems like something else there: `Can't resolve all parameters for ActivatedRoute: (?, ?, ?, ?, ?, ?, ?, ?)`. It fails to include those guys to the `SharedModule` I guess. – Zazaeil Oct 02 '18 at 21:07
  • In that case, I was wrong - take it out of `deps` and don't `@Inject` it. It's already a provider as part of the `RouterModule`, so it should be registered as a provider -- it wasn't meant to be re-registered in your own modules. – joh04667 Oct 02 '18 at 21:13
  • Ok, I fixed that one. Final solution is to do all you've mentioned (thanks) + just expect `Router` into contructor **not mentioning** it in the `providers` section. `Deps` are needed. – Zazaeil Oct 02 '18 at 21:15
  • Yup. I got waaaay off track in my answer, sorry. I'll update it. – joh04667 Oct 02 '18 at 21:24
  • In my case i was using `RouterStateSnapshot`, for that also `ActivatedRoute` needs to be injected. Thanks – Sumanth Shastry Mar 29 '19 at 14:04