I'm trying to work with behaviorSubject to get a username from db with http call. When a user logs in the process should be initialized. And then when a username would change I want to display that without reloading my page to get the updated value. I'm new to the concept and use of BehaviorSubject so this is what I have so far. I created a Authservice that takes the isAuthenticated$(boolean) observable from Auth0Service ( I use auth0 for authenication) and checks if a user is logged in. when a user is logged in it triggers my getLoggedInUser function that contains the http call to fetch the data. But when I want to display the name in sidenav it is null witch is the initial value of behaviorSubject. So I guesse I never make the call to fetch data.
AuthService:
@Injectable({
providedIn: 'root'
})
export class AuthService {
constructor(private api: ApiService, private auth0Service: Auth0Service ) {
this.auth0Service.isAuthenticated$.pipe(tap(isAuth => {
if (isAuth) {
this.getLoggedInUser()
console.log(isAuth)
}
}));
}
private userSubject$ = new BehaviorSubject<any>(null);
user$ = this.userSubject$.asObservable();
getLoggedInUser(): Observable<any> {
return this.api.getCurrentLoggedInUser().pipe(tap(user=> this.userSubject$.next(user)));
}
}
sidenav where I call on user$:
export class SidenavComponent implements OnInit {
constructor(private authService: AuthService) {}
getUser$ : Observable<User>;
ngOnInit(): void {
this.getUser$ = this.authService.user$
}
app component where I first initialize
export class AppComponent implements OnInit {
constructor(public auth0Service: Auth0Service, private authService: AuthService) {}
ngOnInit(): void {
this.authService.user$;
}
}
sidenav html:
<div *ngIf="getUser$ | async as profile">
<h3>{{profile.name}}</h3>
</div>
Could anyone help me understand why I don't get any data?
UPDATE:
I've managed to verify that I first wasn't even getting in the getLoggedInUSer function but now I moved the this.getLoggedInUser() call to my authguard and now I could succesfully log the loggin boolean as true in my getLoggedInUser(). I now tried to log userSubject$ inside of getLoggedInUser() after the api call and I removed return before the call. I get this in console :
BehaviorSubject {_isScalar: false, observers: Array(0), closed: false, isStopped: false, hasError: false, …}
value: (...)
_isScalar: false
observers: [Subscriber]
closed: false
isStopped: false
hasError: false
thrownError: null
_value: null
__proto__: Subject
It seems empty witch is strange because I logged this after the api call
Your service should not call method in constructor this.auth0Service.isAuthenticated$.
. These methods should be separated:
import { HttpClient } from '@angular/common/http';
import {Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class AuthService {
constructor(private api: ApiService,
private auth0Service: Auth0Service ) {}
this.auth0Service.isAuthenticated$
.pipe(map(v => v));
getLoggedInUser(): Observable<any> {
return this.api.getCurrentLoggedInUser()
.pipe(map(v => v));
}
}
And your component can get data from the above service using async
and await
keywords.
your.component.ts:
user: any;
async ngOnInit() {
let isAuthenticated = this.authService.isAuthenticated.toPromise();
if (isAuthenticated) {
this.user = this.authService.getLoggedInUser().toPromise();
console.log(this.user);
}
}
HTML:
<div *ngIf="user">
<h3>{{user | json}}</h3>
</div>
UPDATE:
You can use Observable
for getting recently updated user:
user: any;
ngOnInit() {
this.authService.isAuthenticated.pipe(
tap(val => console.log(val)),
switchMap(val => this.authService.getLoggedInUser())
).subscribe(user => {
this.user = user;
});
}