[Fixed] Hide Toolbar on login component without having to refresh (Angular 11)

Issue

I created a simple Authentication service that works well at the start of the web app , however in a user-case scenario where the user decides to log-out and relog-in the toolbar/navbar remain visible when switching back to the login page, in order for it to become invisible the page needs to be refreshed so the ngIf method would work; my idea was to show the toolbar/navbar whenever the user is logged in, which means if there is a token cached in localStorage.

this is the code that applies the toolbar/navbar

app.component.html

<div class="main" >
    <mat-toolbar  *ngIf="userToken">
      <div class="MenuBar">
        
          <button mat-icon-button style="margin:auto" color="primary" (click)="opened=!opened" aria-label="Example icon button with a menu icon">
            <mat-icon>menu</mat-icon>
          </button>
        
        <button mat-raised-button color="primary" routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}">Home</button>
      </div> 
      
        <span class="spacer"></span>
        <button mat-stroked-button id="Users" style="margin-right: 16px" routerLink="/users" routerLinkActive="active">Profile</button>
        <button mat-raised-button color="accent"  (click)="logout()">Logout</button>
      
    </mat-toolbar>
 
    
    <mat-sidenav-container class="container" >
      <mat-sidenav mode="push"  [(opened)]=opened >
      <p>Working</p>
      </mat-sidenav>
        <mat-sidenav-content>
          <div class="app-container">
            <alert></alert>
            <router-outlet></router-outlet>
          </div>
        </mat-sidenav-content>
      
    </mat-sidenav-container>

app.component.ts

import { Component,ChangeDetectorRef } from '@angular/core';

import { AccountService } from '../app/services/account.service';
import { User } from '../app/models/user';
import { Token } from '@angular/compiler/src/ml_parser/lexer';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})


export class AppComponent {
  title = 'FrontEnd';
  userToken: Token;
 
  opened=false;
  

    constructor(private accountService : AccountService) {
      this.userToken = this.accountService.userToken;
        
        
    }

    
    logout() {
      
      this.accountService.logout();
      
    }

}

app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AppComponent } from './app.component';
import { LoginComponent } from './authentification/login/login.component'
import { MainComponent } from './main/main.component';
import { UsersModule } from './Users CRUD/users.module';
import { AuthGuard } from './_helpers/auth.guard';

const authModule=()=> import('./authentification/authentification.module').then(x => x.AuthentificationModule);
const usersModule = () => import('./Users CRUD/users.module').then(x => x.UsersModule);


const routes: Routes = [
  { path : '', component: MainComponent , canActivate: [AuthGuard]},
  { path: 'users', loadChildren: usersModule, canActivate: [AuthGuard] },
  { path : 'auth',loadChildren: authModule},

  { path : '**', redirectTo:''}
];

@NgModule({
  imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
  exports: [RouterModule]
})
export class AppRoutingModule { }

account.service.ts

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';

import { environment } from '../../environments/environment';
import { User } from '../models/user';

@Injectable({ providedIn: 'root' })
export class AccountService {
    private userSubject: BehaviorSubject<User>;
    public user: Observable<User>;
    readonly BaseURL ='https://localhost:44381/api';
    public subj = new BehaviorSubject({});


    constructor(
        private router: Router,
        private http: HttpClient
    ) {
        this.userSubject = new BehaviorSubject<User>(null);
        this.user = this.userSubject.asObservable();
        
    }

    public get userToken() {
        return JSON.parse(JSON.stringify(localStorage.getItem('user')));
    }

    login(username, password) {
        return this.http.post<User>(`${this.BaseURL}/User/Login`, { username, password });
           /* .pipe(map(user => {
                // store user details and jwt token in local storage to keep user logged in between page refreshes
                localStorage.setItem('user', JSON.stringify(user));
                this.userSubject.next(user);
                return user;
            }));*/
    }


    logout() {
        // remove user from local storage and set current user to null
        localStorage.removeItem('user');
        this.userSubject.next(null);
        this.router.navigate(['/auth/login']);
    }

    GetUser()
    {
        return this.http.get(this.BaseURL+'/UserProfile');
    }

    register(user: User) {
        return this.http.post(`${this.BaseURL}/User/Register`, user);
    }

    getAll() {
        return this.http.get<User[]>(`${this.BaseURL}/users`);
    }

    getById(id: string) {
        return this.http.get<User>(`${this.BaseURL}/UserProfile/${id}`);
    }

  
}

Solution

Thanks to @kin I was able to understand the code better and come up with a solution to my problem.
I Fixed this by setting the user token in localstorage inside the login method in the service.ts file then subscribing to the user in the component.ts file
here’s the code :

account.service.ts

...
login(username, password) {
        return this.http.post<User>(`${this.BaseURL}/User/Login`, { username, password }).pipe(map(user => {
            // store user details and jwt token in local storage to keep user logged in between page refreshes
            localStorage.setItem('user', user.token);
            this.userSubject.next(user);
            return user;
        }));
    }
...

app.component.ts

...
constructor(private accountService : AccountService) {
      
      this.accountService.user.subscribe(x => this.user = x);
        
    }
...

app.component.html

<div class="main" >
    <mat-toolbar  *ngIf="user" >
      <div class="MenuBar">
        
          <button mat-icon-button style="margin:auto" color="primary" (click)="opened=!opened" >
            <mat-icon>menu</mat-icon>
          </button>
        
        <button mat-raised-button color="primary" routerLink="/" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}" (click)="opened=false">Home</button>
      </div> 
      
        <span class="spacer"></span>
        <button mat-stroked-button id="Users" style="margin-right: 16px" routerLink="/users" routerLinkActive="active" (click)="opened=false">Profile</button>
        <button mat-raised-button color="accent"  (click)="logout()">Logout</button>
      
    </mat-toolbar>
 
    
    <mat-sidenav-container  >
      <mat-sidenav mode="push"  [(opened)]=opened >
      <p>Working</p>
      </mat-sidenav>
        <mat-sidenav-content>
          <div class="app-container">
            <alert></alert>
            <router-outlet></router-outlet>
          </div>
        </mat-sidenav-content>
      
    </mat-sidenav-container>

I hope this helps anyone with a similar problem

Leave a Reply

(*) Required, Your email will not be published