Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6 Service is undefined after injecting in Interceptor

I can't find any way to inject my AuthService inside ErrorHandlerInterceptor. It returns me either an "undefined" object after injection, or it throws an error.

This is my ErrorHandlerInterceptor:

import { Injectable } from '@angular/core';
import { AuthService } from '@app/auth.service';
import { StorageService } from '@app/storage.service';

@Injectable({
  providedIn: 'root'
})
export class ErrorHandlerInterceptor implements HttpInterceptor {

  constructor(private authService: AuthService, private storageService: StorageService) {
    console.log(this.authService); // undefined
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(catchError(error => this.errorHandler(error)));
  }

  // Customize the default error handler here if needed
  private errorHandler(response: HttpErrorResponse): Observable<HttpEvent<any>> 
  {
    // ... Various code
  }
}

And this is my AuthService:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { StorageService } from './storage.service';
import { Router } from '@angular/router';

@Injectable({
    providedIn: 'root'
})
export class AuthService {
    constructor(private _http: HttpClient, 
    private storageService: StorageService, 
    private router: Router) { }
}

I tried to list the service in the core.module.ts providers, but errors are thrown:

ERROR RangeError: Maximum call stack size exceeded
at setCurrentInjector (core.js:1382)
at resolveNgModuleDep (core.js:8333)
at _createClass (core.js:8425)
at _createProviderInstance (core.js:8393)
at resolveNgModuleDep (core.js:8356)
at _createClass (core.js:8425)
at _createProviderInstance (core.js:8393)
at resolveNgModuleDep (core.js:8356)
at _createClass (core.js:8425)
at _createProviderInstance (core.js:8393)

Note that I am using the framework ngx-rocket, created by ngx-rocket-generator.

How can I do to fix this issue? Any advices?


UPDATE 1 -- CORE.MODULE.TS

Here is the core.module.ts file.

import { NgModule, Optional, SkipSelf } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http';
import { RouteReuseStrategy, RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

import { ShellComponent } from './shell/shell.component';
import { HeaderComponent } from './shell/header/header.component';
import { RouteReusableStrategy } from './route-reusable-strategy';
import { AuthenticationService } from './authentication/authentication.service';
import { AuthenticationGuard } from './authentication/authentication.guard';
import { I18nService } from './i18n.service';
import { HttpService } from './http/http.service';
import { HttpCacheService } from './http/http-cache.service';
import { ApiPrefixInterceptor } from './http/api-prefix.interceptor';
import { ErrorHandlerInterceptor } from './http/error-handler.interceptor';
import { CacheInterceptor } from './http/cache.interceptor';
import { TokenInterceptor } from './http/token.interceptor';
import { StorageService } from '@app/storage.service';
import { AuthService } from '@app/auth.service';

@NgModule({
  imports: [
    CommonModule,
    HttpClientModule,
    TranslateModule,
    NgbModule,
    RouterModule
  ],
  declarations: [
    HeaderComponent,
    ShellComponent
  ],
  providers: [
    AuthenticationService,
    AuthenticationGuard,
    I18nService,
    HttpCacheService,
    ApiPrefixInterceptor,
    ErrorHandlerInterceptor,
    CacheInterceptor,
    TokenInterceptor,
    {
      provide: HttpClient,
      useClass: HttpService
    },
    {
      provide: RouteReuseStrategy,
      useClass: RouteReusableStrategy
    }
  ]
})
export class CoreModule {

  constructor(@Optional() @SkipSelf() parentModule: CoreModule) {
    // Import guard
    if (parentModule) {
      throw new Error(`${parentModule} has already been loaded. Import Core module in the AppModule only.`);
    }
  }

}
like image 266
Simone Romano Avatar asked Sep 04 '18 11:09

Simone Romano


Video Answer


2 Answers

Looks, like you have to add dependencies for your interceptor. In app.module.ts instead of just edding to provide section ErrorHandlerInterceptor declare you provider in such way:

{
  provide: HTTP_INTERCEPTORS,
  useClass: ErrorHandlerInterceptor,
  multi: true ,
  deps: [AuthService, StorageService]
},

Be careful, the order of services in deps should be the same, like in constructor.

PS. Not sure about Angular 6, but for Angular 8,9 it works perfectly.

like image 123
Petrovich Deferenty Avatar answered Oct 13 '22 02:10

Petrovich Deferenty


Finally, I solved the problem. In the error handler, the dependencies cannot be injected through the constructor. To solve it, you need to do this:

First, import the Injector from @angular/core and your service:

import { Injector } from '@angular/core';
import { AuthService } from '@app/auth.service';

Then, you have to inject it in the constructor:

constructor(private modalService: NgbModal, private injector: Injector) { }

And then you have to instantiate your service and use it like this:

const authService = this.injector.get(AuthService);
authService.logout();

The code, is going to be similiar to this:

import { Injector } from '@angular/core';
import { Router } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class ErrorHandlerInterceptor implements HttpInterceptor {

  private authService: AuthService;

  constructor(private modalService: NgbModal, private router: Router, private injector: Injector) { }
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(catchError(error => this.errorHandler(error)));
  }

  // Customize the default error handler here if needed
  private errorHandler(response: HttpErrorResponse): Observable<HttpEvent<any>> {
    this.authService = this.injector.get(AuthService);
    ... Other code ...
}

Hope you have been helped by this answer!

like image 21
Simone Romano Avatar answered Oct 13 '22 02:10

Simone Romano