Skip to content

Trouble with Angular ngOnInit

I have an app that I inherited from somebody that left our organization. I’m having a problem with ngOnInit not working the way I think it should. I’m still pretty new using Angular and Observables

I can see in the console when I navigate to the component it entering the ngOnInit method, what I don’t see is the console.info statement in the subscribe for the response being executed. Once I’m in the component, I can refresh the page and then I can see the console.info statement in the subscribe.

My question is why don’t I see the console.info statement when I first navigate to the component?

Component ngOnInit() method

    ngOnInit(): void {

      console.info('Entering ngOnInit - Home Component');

      this.profile.getProfile().subscribe((resp) => {

          this.currentUser = this.local.getObject(StorageItems.UserProfile) as IMSALUserProfile;

          console.info('Current User: ', + JSON.stringify(this.currentUserInit));
      });
    }

This is what my service looks like, it’s a service that is fetching user profile information from Azure Active Directory using MSAL.

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BaseService } from './base.service';
import { AuthError } from '@azure/msal-browser';
import { LoggerService } from './logger.service';
import { Observable, of } from 'rxjs';
import { IMSALUserProfile } from '../../shared/interfaces/msaluserprofile';
import { SessionService } from './session.service';
import { StorageItems } from '../../shared/interfaces/enums/storage.model';
import { LocalStorageService } from './local-storage.service';
import { UserService } from './user.service';
import { IUserInit } from '../../shared/interfaces/userinit';

@Injectable({
  providedIn: 'root'
})
export class UserProfileService extends BaseService {

  currentUser!: IMSALUserProfile;
  currentUserInit!: IUserInit;

  constructor(private http: HttpClient, 
      private logger: LoggerService, 
      private session: SessionService,
      private local: LocalStorageService, 
      private userInit: UserService) {
    super();
  }

  public getProfile(): Observable<IMSALUserProfile> {

    let sessionUser = this.session.getItem(StorageItems.UserProfile);

    if (sessionUser.length !== 0) {
      this.currentUser = JSON.parse(this.session.getItem(StorageItems.UserProfile));
    }

    let profile!: IMSALUserProfile;

    if (this.currentUser) {
      
      profile = this.currentUser as IMSALUserProfile;
    } else {
      this.http.get('https://graph.microsoft.com/v1.0/me')
      .subscribe({
        next: (profile) => {
          profile = profile;

          this.local.setItem(StorageItems.UserProfile, profile);
          this.session.setItem(StorageItems.UserProfile, JSON.stringify(profile));

          this.currentUser = profile as IMSALUserProfile;
        },
        error: (err: AuthError) => {
          console.info('Authentication error');
        }
      })
    }

    this.local.setItem(StorageItems.UserProfile, profile);
    this.session.setItem(StorageItems.UserProfile, JSON.stringify(profile));

    return of(profile);
  }
}

Answer

You’re returning of(profile) when profile is just undefined. If this.currentUser doesn’t exist, and the else block is executed, you’re trying to set your return value asynchronously. Likely the function returns before the http.get can ever finish.

Rather than subscribing in the service, you probably want to return the http request and pipe it through some RxJS operators to do whatever logic you’re currently doing in the subscribe inside the else block.