I'm trying to add a loginLoading observable where any component can subscribe to it to find weather a user is currently logging in or not.
In my app.component.html
:
<mat-toolbar [ngClass]="{'disable-pointer': loginLoading}">
<a routerLink="login" routerLinkActive="active" id="login"> Login </a>
</mat-toolbar>
In my app.component.ts
:
public loginLoading;
constructor(private authenticationService: AuthenticationService) {}
ngOnInit() {
this.authenticationService.loginLoading.subscribe(loginLoading => {
this.loginLoading = loginLoading;
})
}
In my login.component.ts
:
constructor(private authenticationService: AuthenticationService){}
ngOnInit(): void {
this.authenticationService.loginLoading.subscribe(loginLoading => this.loginLoading = loginLoading)
this.authenticationService.login().subscribe(
data => {
this.router.navigate([this.state],);
console.log(`after: ${this}`)
},
error => {
this.loginFailed = true
this.error = error.non_field_errors[0]
});
}
In my AuthenticationService
:
private loginLoadingSubject: BehaviorSubject<boolean>;
public loginLoading: Observable<boolean>;
constructor(private http: HttpClient) {
this.loginLoadingSubject = new BehaviorSubject<boolean>(false);
this.loginLoading = this.loginLoadingSubject.asObservable();
}
login() {
this.loginLoadingSubject.next(true)
return this.http.post<any>(`${environment.apiUrl}/login`, {....})
.pipe(map(user => {
.
.
this.loginLoadingSubject.next(false)
.
.
}),
catchError(error => {
this.loginLoadingSubject.next(false)
return throwError(error);
}));
}
Also here is a very simplified example on stackblitz.
My question is why doesn't angular detect the change in the app's component loginLoading
field
in this line this.loginLoading = loginLoading;
? Shouldn't this trigger a change detection cycle?
Also if I move the code in the LoginComponent
's ngOnInit()
to the LoginComponent
's constructor the error does not appear, does this mean that angular checks for changes after the constructor and befor the ngOnInit()
?
I solve this by running change detection manually after this line this.loginLoading = loginLoading;
in the AppComponent
but i'd prefer if i don't or at least know why should I.
Edit: I understand that in development mode, angular checks the model didn't change using 1 extra check. What I assumed would happen is since an observable firing a new value would trigger a new change detection cycle the error shouldn't appear.
To my understanding that if an observable fire between the 2 checks (and it's value is bound to the view), angular wouldn't know (and wouldn't trigger change detection again) and therefore the error appears after the second check