Unable to retrieve user data from store in Angular fire auth upon refreshing the page

Utilizing Firebase Authentication for email and password sign up.
The login function is performing effectively, with the following call:

await setPersistence(this.auth, browserLocalPersistence);

Upon logging in, the user data is saved to firestore after creating a new user.

The issue at hand:

Within my auth.service.ts, I am attempting to retrieve the user document based on the auth.currentUser. The currentUser from Firebase is consistently retrieved whenever required.

This is how it's done:

this.auth.onAuthStateChanged(user => {
  console.log('FIRE AUTH ON AUTH STATE CHANGED RUNNING', user);
  if (user) {
    this.user$ = of(user).pipe(
      switchMap(async user => {
        try {
          const res = await getDoc(doc(this.db, 'users', user.uid));
          console.log(res.data());
          return res.data() as FireUser;
        } catch (error) {
          console.error(error);
          return null;
        }
      })
    );
  } else {
    this.user$ = of(null);
  }
});  

Initially, it works well after login. However, upon a refresh (with currentUser still being retrieved correctly), the function ceases to proceed further without any errors or notifications. It simply does not enter the switchMap block.

I confirm that the currentUser value is correctly logged right at the beginning of onAuthStateChanged..

(Alternative approach used):

onAuthStateChanged(this.auth, user => {
  console.error('USER IS', user);
  if (user) {
    this.user$ = docData(
      doc(this.db, 'users', user.uid)
    ) as Observable<FireUser>;
  } else {
    this.user$ = of(null);
  }
});

To display the user$ Observable data in a component like so:
TS:

user$ = this.fireAuthService.user$;  

HTML:

  <div *ngIf="user$ | async as user">
    <pre>
     {{ user | json }}
   </pre>
  </div>

What might be causing the problem?

Hence, my solution (based on @Werner7's answer):

  private userSubject$ = new BehaviorSubject<FireUser>(null);

  get user$(): Observable<FireUser> {
    return this.userSubject$.asObservable();
  }

    onAuthStateChanged(this.auth, async user => {
      console.error('USER IS', user);
      if (user) {
        this.userSubject$.next(
          (await getDoc(doc(this.db, 'users', user.uid))).data() as FireUser
        );
      } else {
        this.userSubject$.next(null);
      }
    });

Answer №1

I utilize behaviorSubject in my approach, which I find appealing due to its dynamic nature.

export class AuthService {

  private readonly user$ = new BehaviorSubject<UserModel | null>(null);

  private _internalUserTmp: UserModel;

  public get internalUserTemp(): UserModel {
    return this._internalUserTmp;
  }
  private set internalUserTemp(value: UserModel) {
    this._internalUserTmp = value;
  }

  get currentUser(): Observable<UserModel | null> {
    return this.user$.asObservable();
  }

constructor(
    private readonly auth: Auth,
    private readonly firestore: Firestore,
    private readonly functions: Functions) {
    onAuthStateChanged(this.auth, user => {
      // console.log("State Chaned: ", user);
      this.retrieveUserData(user);
      auth.currentUser?.getIdTokenResult().then(idTokenResult => {
        // console.log(idTokenResult);
        if (!!idTokenResult.claims.superAdmin) {
          this._isSuperAdmin$.next(true);
          this._isAdmin$.next(true);
        } else if(!!idTokenResult.claims.admin){
          this._isAdmin$.next(true);
          this._isSuperAdmin$.next(false);
        }else {
          this._isAdmin$.next(false);
          this._isSuperAdmin$.next(false);
        }

      })
    });
    this.user$.subscribe(user => {
      this.internalUserTemp = user as UserModel;
    });
}

private async retrieveUserData(user: User | null): Promise<void> {
    if (!user) {
      this.user$.next(null);
      return;
    }
    if (user.email === undefined || null || '') {
      this.user$.next(null);
      return;
    }
    await this.getUserDataByEmail(user.email ? user.email : '').subscribe(
      userData => {
        this.user$.next(userData);
      }
    );
  }

getUserDataByEmail(email: string) {
    return docData(doc(this.firestore, "users/", email));
  }

In addition, I make use of UserModel that is structured as follows...

export class UserModel extends BaseModel {
    uid?: string | null;
    auth_id?: string | null;
    adminReview?: boolean | null;
//...

constructor(config?: UserModel) {
  super();
  config = Object.assign({}, config);
  this.uid = config.uid;
  this.auth_id = config.auth_id;
  this.adminReview = config.adminReview;
//...
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Guidance on showcasing user details post-login authentication using NodeJS and express

Utilizing Cloud Firestore as the database for my project, I have created frontend components using HTML, CSS, and JS. Currently, I am focused on developing the backend functionalities. Successfully implementing registration functions for both doctors and p ...

What steps can be taken for TypeScript to identify unsafe destructuring situations?

When working with TypeScript, it's important to prevent unsafe destructuring code that can lead to runtime errors. In the example below, trying to destructure undefined can cause a destructuring error. How can we ensure TypeScript does not compile suc ...

Exploring the power of Firebase with Vue Js lifecycle methods

I am attempting to retrieve data from a specific user in Firebase and push that data into designated input fields. The path in Firebase is located here: var query = db.ref('Clients/'+ clientName +'/form/'); I retrieve the data in the ...

Leveraging angular2-material with systemjs for Angular2 development

After completing the TUTORIAL: TOUR OF HEROES on this link, I attempted to integrate angular2-material into my project. Unfortunately, I am having issues with the CSS not displaying correctly. Can anyone provide insight into what I may be missing or doing ...

What steps should be taken to identify a new path following a call to router.navigate?

Trying to interrupt a route change using a router guard. When I use: this.router.navigate([“myApp/userProfiles”]); After calling this, it passes through the CanDeactivate interface of the guard. The guard then needs to determine the actual destinatio ...

Issue encountered with asynchronous waiting while invoking a function

var value = await this.upload(); if (value == true) { // Update item properties this.item.photos = this.uploaded; this.item.price = null; this.item.qty = null; // Add item to data service this.dataSrv.addItem(this.item) .then(() => { ...

Looking for recommendations on the best tools to use for starting an Angular 2 project?

After successfully creating an Angular 2 web app on my computer, I encountered a problem when trying to build it for production. Instead of using my project files, angular-cli generated a "Hello World" app. The confusion arose because I was initially using ...

The Angular Material Stepper ng-template is missing a defined context variable for custom icons which is causing

My endeavor involves leveraging an ng-template alongside the matStepperIcon property to customize Angular Material's matStepper icons. I am also aiming to transmit some data by utilizing ng-container and *ngTemplateOutlet, yet facing partial success. ...

Is there a method to automatically select or deselect a checkbox based on the incoming value in Angular?

When new data comes in, the table gets populated and I can't specify that "A" should be checked while "D" shouldn't. re(ref: getrefactormodel, count:number){ let data= this.fb.group({ word_to_rename: [ref.word_to_rename, Vali ...

Setting a TypeScript type recursively to allow for changes without affecting tuples

export type DraftObject<T> = {-readonly [P in keyof T]: Draft<T[P]>} export interface DraftArray<T> extends Array<Draft<T>> {} export type Draft<T> = T extends any[] ? DraftArray<T[number]> : T extends Read ...

Unable to employ the .some() method with an array consisting of objects

I am currently attempting to determine whether my array of objects contains an attribute with a specific value. I wanted to use the array.some() method instead of a foreach loop, but I keep encountering an error: Error TS2345: Argument of type '(ele ...

Error in AngularX TS: Trying to invoke a type that does not have a callable signature

Encountering an issue while working on a component, specifically during ng serve/build process. Please note that this error is different from any console errors, despite what some may think. The expected outcome is for the code to successfully build and ru ...

Enhancing communication between Angular 4 services

Two of my main services are SharedDataService (SDS) and FilterService (FS). SDS is responsible for managing API requests related to user data, employee information, and observations. On the other hand, FS handles various on-screen functionalities. Ideally, ...

Tips for generating a hyperlink in a Typescript file using Angular version 16 and above

I am encountering an issue with my consts.ts file in the project. Specifically, I have defined a constant LINK1 as <a href='https://sample.com/'>LINK 1</a>; However, this setup is not working as expected. What I actually want is to d ...

Error message "The result of this line of code is [object Object] when

Recently, I encountered an issue while retrieving an object named userInfo from localStorage in my Angular application. Despite successfully storing the data with localStorage.setItem(), I faced a problem when attempting to retrieve it using localStorage.g ...

Retrieve only data that results in either a 1 or 0 when filtering

Currently, I am utilizing Angular2 with Typescript and making use of the filter method. The functionality of the filter() method involves creating a new array that contains elements which successfully pass the test defined by the given function. However, ...

Karma - Error: No provider found for HttpClient in NullInjectorError

I'm encountering a NullInjectorError: No provider for HttpClient when running my test. I am using Angular 8 with Karma and despite following examples, I am new to Karma and unsure of why this error is occurring. Can anyone shed some light on this issu ...

What steps should I take to resolve the Typescript error indicating "module" cannot be found?

I have encountered a unique issue with a React Component that I developed myself. Unlike similar problems discussed in resolutions, this particular problem seems to be specific to my code. import React from 'react'; import { useForm } from " ...

`On the first date chosen, activate an event within the ngx-bootstrap daterangepicker.`

I am utilizing a date range picker with the following code: <bs-daterangepicker-inline [bsValue]='bsValue' (bsValueChange)="test()"></bs-daterangepicker-inline>. Is there a way to trigger an event when the first date is sel ...

Ways to successfully transfer values or variables from within onAuthStateChanged

Currently, I am attempting to retrieve the authenticated user's uid from Google authentication for a specific collection in the "User" document. To ensure that the data does not become null after refreshing the webpage, I am utilizing onAuthStateChang ...