Hayden
Hayden

Reputation: 857

How do I get a value in a BehaviorSubject to return within a getter?

From my understanding, when you subscribe to a BehaviorSubject, that subscription is asynchronous. I am trying to get a value from an object within a BehaviorSubject and return that value in a getter. The getter needs to return the type 'number'. How do I approach this?

Below, I have a getter userId, which should return the user Id from an object held in the BehaviorSubject _loggedInUser

export class AuthServiceService {

  private _loggedInUser: BehaviorSubject<LoggedInUserData> = new BehaviorSubject(null);

  constructor(
    private http: HttpClient, 
    private storage: Storage
  ) { }


 /// This method below!!! --------------

  public get userId(): number{

    this._loggedInUser.pipe(
      take(1), 
      map(((loggedInUserData: LoggedInUserData) => {
        if(loggedInUserData){
          return loggedInUserData.user_id
        }
        return null;
      }))
    ).subscribe((userId: number | null) => {
      return userId;
    });
    
  }
  
 //// -----------------


  public doLogin(loginData: LoginFormData): Observable<any>{

    return this.http.post<LoggedInUserData>(`${authURL}/token`, loginData)
    .pipe(
      catchError(err => {

        if(err.status && err.status === 403)
          return throwError('The credentials you have entered are invalid or do not exist.');
        else
          return throwError('There was an issue processing your request.');

      }), 
      tap(respData => {

        console.log('LOGGED IN USER DATA: ', respData);

        this._loggedInUser.next(respData);
        this.storage.set('userData', respData);

      })
    );



  }


  public async autoLogin(){



  }


  public doLogout(){




  }





}

Upvotes: 3

Views: 3675

Answers (3)

North Halcyon
North Halcyon

Reputation: 127

Another approach - convert Observable to Promise, then use async/await:

const user = await this._loggedInUser.toPromise();
return user && user.userId;

Upvotes: 0

skolic
skolic

Reputation: 123

If you simply need the result synchronious, you should use the example as provided by Rafi Henig:

    public get userId(): number {
      return this._loggedInUser.getValue()?.userId
    }

If you want it to be async, you could return an Observable<number> instead and use an async pipe in your html if you need to show it there. If not, you can subscribe to that Observable where you need it or keep the subscription if you want to track changes of the value. I am not sure if this is what you want, but here is an example of that:

  public get userId(): Observable<number> {
    return this._loggedInUser.pipe(
      map((item) => item?.userId)
    );
  }

For HTML, use: {{ userId | async }} and for typescript code you can use:

    this.userId.pipe(take(1)).subscribe((userId) => {
      console.log(userId);
    });

If you want to keep track the changes in your typescript, you should remove take(1) and simply subscribe to it. Remember to clean the subscription in ngOnDestroy.

Upvotes: 0

Rafi Henig
Rafi Henig

Reputation: 6414

Having an access to the Subject, you can obtain its value synchronously via getValue() mothod, as following:

public get userId(): number {
  return this._loggedInUser.getValue()?.userId
}

Upvotes: 4

Related Questions