0

I have an issue with my authservice. If I make a http request inside constructor it is called 259 times. If I remove the http call it is called one time. I use a shared module to provide a unique instance of that service.

Angular version: 4.4.4

Console print

Here is my sharedModule:

export const providers = [
  AuthService,
  DataStorageService,
];

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    HttpClientModule,
    ReactiveFormsModule,
    InfiniteScrollModule,
    TruncateModule
  ],
  declarations: [
    FooterComponent,
    PhotoListComponent,
    GalleryListComponent,
     ],
  exports: [
    FooterComponent,
    PhotoListComponent,
    GalleryListComponent,
    InfiniteScrollModule,

  ],
  providers: [
    
    ]})

export class SharedModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: SharedModule,
      providers: [...providers]
    };
  }
}

And my AuthService:

@Injectable()
export class AuthService {

  public session: Subject<SessionModel> = new Subject<SessionModel>();
  private cachedSession: SessionModel = new SessionModel(null, null, false);
  private apiUrl = 'http://localhost:8080/Galleo/user/login';


   constructor(private cookieSrv: CookieService,
              private http: HttpClient) {
    console.log('constructor called');
    if (this.cookieSrv.get('system-g-unx-data')) {
      const cook = atob(this.cookieSrv.get('system-g-unx-data')).split('||');
      const username = cook[0];
      const password = cook[1];
      this.login(username, password);
    }
  }

  // login method, call REST API and store cookie into user Browser
  login(username: string, password: string) {

    const user: UserModel = new UserModel();
    user.userName = username;
    user.password = password;

    const headers = new HttpHeaders();
    headers.append('Content-Type', 'application/json');

    this.http.post<UserModel>(this.apiUrl, user, {observe: 'response', headers: headers}).subscribe(
      (response) => {
        console.dir(response);
        this.cachedSession.user = response.body;
        this.cachedSession.token = response.headers.get('Authorization');
        this.cachedSession.isAuthenticated = true;
        this.session.next(this.cachedSession);
        this.cookieSrv.put('system-g-unx-data', btoa(username + '||' + password));
      },
      (error) => {
        console.dir(error);
        this.session.next(null);
      }
    );
   }
  }

Thanks!

EDIT: I found the problem. Is coming from AuthInterceptor. When i try to get the authorization token it start an infinite loop:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private authService: AuthService;
  constructor(private injector: Injector) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log('Intercepted!', req);
    this.authService = this.injector.get(AuthService);

    const request = req.clone({
      setHeaders: {
        Authorization:  `${this.authService.getSession().token}`
      }
    });

    return next.handle(request);

  }
}

Now how can I recover the authService inside Interceptor without using injector?

FINAL EDIT: I figured out how to get the token from my authService without making an infinite loop. The problem was my HttpInterceptor that I used for add token to Authorization Header for each request. In my AuthService constructor I was calling the login method that make an http request.. LOOP: INTERCEPTOR => AUTH SERVICE => HTTP CLIENT and again INTERCEPTOR

So, now I make some checks in my interceptor like:

Injectable()
export class AuthInterceptor implements HttpInterceptor {
  private authService: AuthService;
  constructor(private injector: Injector) {  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    // If login method called skip and continue request
    if (req.url.includes('login')) {
      return next.handle(req);
    }

    // If request don't have the Authorization Header, add the token to the header
    if (!req.headers.has('Authorization')) {
      this.authService = this.injector.get(AuthService);
      const request = req.clone({
        setHeaders: {
          Authorization: `${this.authService.getSession().token}`
        }
      });
      return next.handle(request);
    }

    return next.handle(req);
  }

Maybe can help somebody that will have the same issue. PS: The injector need to be called after the checks

Thanks for help!

LW001
  • 2,452
  • 6
  • 27
  • 36
Verso Alex
  • 11
  • 1
  • 2
  • "The constructor method on an ES6 class (or TypeScript in this case) is a feature of a class itself, rather than an Angular feature": https://toddmotto.com/angular-constructor-ngoninit-lifecycle-hook Consider using `constructor` mainly for dependency injection, use `ngOnInit`for your logic instead – t3__rry Oct 11 '17 at 15:54
  • ngOnInit is not called on service... – Verso Alex Oct 11 '17 at 18:29

1 Answers1

1

Create a core/core.module.ts where you import it once in your app.module.ts

import { CommonModule } from '@angular/common';
import {
  ModuleWithProviders, NgModule,
  Optional, SkipSelf
} from '@angular/core';


import { AuthGuard } from '../guards/auth.guard';
import { AuthService } from '../services/auth.service';

@NgModule({
  imports: [CommonModule],
  declarations: [],
  exports: [],
  providers: [AuthGuard, AuthService]
})

export class CoreModule {

  constructor( @Optional() @SkipSelf() parentModule: CoreModule) {
    if (parentModule) {
      throw new Error(
        'CoreModule is already loaded. Import it in the AppModule only');
    }
  }

  static forRoot(): ModuleWithProviders {
    return {
      ngModule: CoreModule,
      providers: [
        AuthService,
        AuthGuard,
      ]
    };
  }
}

There is a check to make sure it is only loaded once.

app.module.ts

import {CoreModule} from './core/core.module';

@NgModule({
  declarations: [
  ],
  imports: [
    CoreModule.forRoot(),
  ],
  providers: [

  ],
  bootstrap: [AppComponent]
})

its referenced as a singleton in the docs under "The Core Module" https://angular.io/guide/ngmodule

Kay
  • 17,906
  • 63
  • 162
  • 270
  • This don't work.. is the same thing.. You have tried to make a http request inside? the http client where i need to declare? – Verso Alex Oct 11 '17 at 18:27