Reputation: 857
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
Reputation: 127
Another approach - convert Observable to Promise, then use async/await:
const user = await this._loggedInUser.toPromise();
return user && user.userId;
Upvotes: 0
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
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