I am trying to create a basic login/logout system in my angular application with basic functions such as:
I have a fastify server which is connected to a mongodb database, this works fine, I can log in and a JWT is returned to the frontend. I am having issues with getting my UI to update when the user is logged in or logged out. For simplicity sake(I will refactor once i figure out this issue), I am driving the UI changes purely based on whether a token is present.
auth/user service:
@Injectable({
providedIn: 'root',
})
export class UserService {
router = inject(Router);
http = inject(HttpClient);
private tokenSubject = new BehaviorSubject<string | null>(null);
public token: Observable<string | null> = this.tokenSubject.asObservable();
constructor() {
const storedToken = localStorage.getItem('token');
if (storedToken) {
this.tokenSubject.next(storedToken);
}
}
public get tokenValue(): string | null {
return this.tokenSubject.value;
}
login(login: Login): Observable<UserToken> {
return this.http.post<UserToken>(`${environment.apiUrl}/login`, login).pipe(
map((token) => {
console.log('token', token);
localStorage.setItem('token', token.token);
this.router.navigate(['/test']);
return token;
})
);
}
logout(): void {
localStorage.removeItem('token');
this.tokenSubject.next(null);
this.router.navigate(['/login']);
}
register(user: SignUp): Observable<string> {
return this.http.post<string>(`${environment.apiUrl}/register`, user);
}
}
After I am logged in and a token is returned, I want to hide the login button which is used in my navigation component:
<div class="navbar bg-base-100">
<div class="flex-1">
<a class="btn btn-ghost text-xl" routerLink="/">Kilvey League</a>
</div>
<div class="flex-none">
<ul class="menu menu-horizontal px-1">
@if(!(isLoggedIn$ | async) ){
<li routerLink="/signup" routerLinkActive="['active']">
<a>Sign Up</a>
</li>
<li routerLink="/login"><a>Login</a></li>
} @else {
<li routerLink="/create-match"><a>Create Match</a></li>
<li (click)="logout()"><a>Logout</a></li>
}
</ul>
</div>
</div>
export class NavigationComponent {
userService = inject(UserService);
isLoggedIn$ = this.userService.token;
async logout() {
await this.userService.logout();
}
}
This uses the token from the userservice but after login and routes to /create-match
, the login button still persist. If i refresh, login changes to logout but i want it to change in real time.
As per the code you shared, I think the token
observable from UserService
is not being updated after a successful login.
Updating it would emit a new value through the token
observable and the sign up / login buttons should hide
login(login: Login): Observable<UserToken> {
return this.http.post<UserToken>(`${environment.apiUrl}/login`, login).pipe(
map((token) => {
console.log('token', token);
localStorage.setItem('token', token.token);
this.tokenSubject.next(token); // <- update token observable
this.router.navigate(['/test']);
return token;
})
);
}