I have a boolean BehaviorSubject whose value I want to use in my template:
isLoggedIn$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
in ngOnInit, I subscribe to it:
this.isLoggedIn$.subscribe((result) => {
console.log('result', result);
});
Following that (in the ngOnInit), I have a service call that returns a promise. When that is done, I set the behavior subject value:
this.authService.isLoggedIn().then((loggedIn) => {
if (loggedIn) {
this.isLoggedIn$.next(loggedIn);
console.log('loggedIn', loggedIn);
// set the user model value here...
}
});
Lastly, I am displaying this value in the template:
<span>{{ isLoggedIn$ | async }}</span>
However, even though the console is showing the value changing, the template is not updating. I tried ngAfterViewInit and change detection and nothing seems to work. I assume the reason the value isn't updating in the template is becasue angular doesn't think anything has changed when the behavior subject is updated.
Am I missing something?
The problem is it might take a second or two to get the value back from the authService.isLoggedIn promise and if it is delayed longer that, the template wont display data (login info, like the user name) from the promise. The only thing that works is if I use a setTimeout() wrapper around the service call, which I would prefer not to do.
Any suggestions?
EDIT: here is the whole component, adding the Observable as suggested by Brandon. Still doesn't work though:
import { Component, OnInit } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { IUserModel } from './_interfaces/user';
import { AppService } from './_services/app.service';
import { AuthService } from './_services/auth.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
apiUser?: IUserModel;
isLoggedIn$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
isLoggedInOb: Observable<boolean> = new Observable<boolean>;
constructor(
private readonly authService: AuthService,
private readonly appService: AppService) {
}
ngOnInit(): void {
this.isLoggedInOb.subscribe((result) => {
this.isLoggedIn = result;
console.log('result', result);
});
setTimeout(() => {
this.authService.isLoggedIn().then((loggedIn) => {
this.isLoggedIn$.next(loggedIn);
this.isLoggedInOb = this.isLoggedIn$.asObservable();
console.log('loggedIn', loggedIn);
this.appService.lastActivityDatetimeSubject$.subscribe((data) => {
this.lastActivityDatetime = data;
});
});
}, 0);
this.appService.apiUserSubject$.subscribe((data) => {
this.apiUser = data;
});
}
login(): void {
this.authService.login();
}
logout(): void {
this.authService.logout();
}
}
If I set the setTimeout to 1000 milliseconds, it works but not if I remove the setTimeout function.
Here is the template:
<header>
<div >
<a href="index.html" >
<img src="assets/images/logo.png" alt="Company Logo" />
</a>
<div >
<span >Company Name</span>
</div>
</div>
<div>
<div >
<div >
<span>App Name</span>
</div>
<div >
<span *ngIf="apiUser && isLoggedIn && apiUser.FirstName">Hello {{apiUser.FirstName}} {{apiUser.LastName}}!</span>
<button *ngIf="!isLoggedIn" mat-stroked-button (click)="login()">Login</button>
<button *ngIf="isLoggedIn" mat-stroked-button (click)="logout()">Logout</button>
{{ isLoggedInOb | async }} <--- this is what I am trying to have updated when the behavior subject is updated
</div>
</div>
</div>
</header>
<div role="main">
<router-outlet></router-outlet>
</div>
<footer role="contentinfo">
<div >
<a href="/disclaimer">Disclaimer</a>
<span aria-hidden="true">|</span>
<a href="/privacy-policy">Privacy Policy</a>
<span aria-hidden="true">|</span>
<a href="/terms-conditions">Terms and Conditions</a>
</div>
</footer>
CodePudding user response:
I typically provide an observable for the Subject/BehaviorSubject:
isLoggedIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
isLoggedIn$: Observable<boolean>;
constructor() {
this.loggedIn$ = this.isLoggedIn.asObservable();
}
Then components subscribe to the observable, not the Subject/BehaviorSubject directly.
CodePudding user response:
try to use this logic code :
IN THE SERVICE :
private isLoggedIn: BehaviorSubject<boolean> = new
BehaviorSubject<boolean>(false);
isLoggedIn$ = this.isLoggedIn.asObservable();
isLoggedIn(){
return this.http.post(url).pipe(
map(data)=>{
//...code
this.isLoggedIn.next(data)
//...code
}
)
}
IN THE COMPONENT
currentUser$:Observable<UserInteface>
ngOnInit(): void {
this.currentUser$= this.service. isLoggedIn$
}
IN THE HTML you can subscribe to it and unsub using the async pipe
<div *ngIf="(currentUser$ | async) as user">
{{user.nameExemple}}
//some code
</div>