I have a component that shows the logged in status simply like this:
{{loggedIn()}}
the .ts code is as follows:
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, WritableSignal } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatIconModule } from '@angular/material/icon';
import { RouterOutlet } from '@angular/router';
import { CompanyLoginComponent } from './company-login/company-login.component';
import { AuthService } from './auth.service';
import { AsyncPipe } from '@angular/common';
import { MatSidenavModule } from '@angular/material/sidenav';
@Component({
selector: 'app-company-facing',
standalone: true,
imports: [
MatToolbarModule,
MatButtonModule,
MatIconModule,
RouterOutlet,
CompanyLoginComponent,
AsyncPipe,
MatSidenavModule,
],
templateUrl: './company-facing.component.html',
styleUrl: './company-facing.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [AuthService,]
})
export class CompanyFacingComponent {
constructor(private auth: AuthService,
private cdr: ChangeDetectorRef,
) {
}
get loggedIn() {
return this.auth.loggedIn;
}
async logout() {
await this.auth.logout();
}
forceChangeDetection() {
this.cdr.detectChanges(); // Where cdr is ChangeDetectorRef injected in your constructor
}
}
here's my auth service:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { firstValueFrom } from 'rxjs';
import { signal, WritableSignal } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class AuthService {
loggedIn: WritableSignal<boolean> = signal(false);
constructor(
private http: HttpClient,
) {
this.loggedIn.set(!!localStorage.getItem('accessToken'));
}
async login(email: string, password: string) {
let res = await firstValueFrom(
this.http.post<{ access_token: string }>('https://api.self-serve.just-solve.com/api/login',
{
email,
password
})
)
console.log(res);
if (res.access_token) {
this.loggedIn.set(true);
console.log("logged in updated to true!");
//FIXME: wHY NOT WORKING CHANGE DETECTION on company-facing.component.ts??? when it log out, it works, when log in, it stays stuck and you have to refresh page ç_ç
}
console.log(this.loggedIn())
localStorage.setItem('accessToken', res.access_token);
return res;
}
async logout() {
try {
let res = await firstValueFrom(
this.http.post('https://api.self-serve.just-solve.com/api/logout', {})
);
this.loggedIn.set(false);
}
catch (e) {
console.error(e);
}
localStorage.removeItem('accessToken');
}
}
The problem is: When i log out, the logged in display correctly switches to false. When i log in, it stays to true, and i have to refresh the page to make it update. How come? How can i make it update also when i log in and not only when i log out?
Solved!
I had written providers: [AuthService]
within the @Component
decorator, which led to AuthService being instantiated per component, rather than as a singleton across the entire application.
As a result, the logout functionality worked as expected because it was invoked from the same component instance that initiated the AuthService. However, the login action, triggered from a different component, was operating on a separate instance of AuthService.
This created a discrepancy where the login updated a different instance of the loggedIn value, which was not being observed by the main component.
To solve this, I removed providers: [AuthService]
from all the @Component decorators and ensured AuthService is provided at the application level, by using providedIn: 'root'
in the @Injectable decorator of the AuthService. This change ensures that a single instance of AuthService is used throughout the application, maintaining consistent state across components.