Anas Masti
Anas Masti

Reputation: 38

Angular 8 - How to keep behavior subject data on page reload

I'm trying to get the current user as an observable in the authentication service, so I want to display the current user even though the page is reloading

Everything is working fine, but I cannot get current user after page reload

On AuthService:

  private currentUserSubject: BehaviorSubject<any>;
  public currentUser: Observable<any>;

  constructor(private httpClient: HttpClient,public router: Router) {
    this.currentUserSubject = new BehaviorSubject(JSON.parse(localStorage.getItem('currentUser')));
    this.currentUser = this.currentUserSubject.asObservable();
   }



login(user: User) {
  return this.httpClient.post<any>(`${this.API_URL}/users/login`, user)
    .subscribe((data: any) => {
      localStorage.setItem('access_token', data.token)
      this.getUserProfile(data.user._id).subscribe((res) => {

  --->>>> this.currentUserSubject.next(res.nom);

        this.router.navigate(['/profile/' + res._id]);
      })
    })
}

On PageComponent:

 currentuser;

  ngOnInit() {
      
        this.currentuser = this.authService.getCurrentUser()
        console.log("my user s heeere " + this.currentuser)
        
  }

Result

my user heeere JOETEST

After page reload

my user heeere null

Upvotes: 1

Views: 6520

Answers (4)

abhay tripathi
abhay tripathi

Reputation: 4022

To handle User session Build a dedicated Auth Functionality

It follows the separation of concern and single responsibility principle and makes your code highly maintainable. I am posting a complete solution for later reference.

auth.service.ts

import { Injectable, PLATFORM_ID, Inject } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { AuthApiService } from '../api/auth.api';
import { tap, take, first } from 'rxjs/operators';
import { isPlatformBrowser } from '@angular/common';

@Injectable({
    providedIn: 'root'
})
export class AuthService {

    private readonly CAH_TOKEN = 'CahToken';
    private readonly CAH_USERNAME = 'username';

    private logger: BehaviorSubject<boolean> = new BehaviorSubject(false);

    constructor(private api: AuthApiService, @Inject(PLATFORM_ID) private platformId) {
        this.logger.next(this.isUserLoggedIn());
    }

    /** Subscribe to know automatically whenever login status changes */
    public isLoggedIn = () => this.logger.asObservable();
    public logout = () => this.api.logout().pipe(tap(_ => this.deleteUser()));
    public login = (username, password) => this.api.login(username, password).pipe(tap(_ => { if (_.success) { this.saveUser(_); } }));

    public getToken = () => localStorage.getItem(this.CAH_TOKEN);
    public getUserName = () => localStorage.getItem(this.CAH_USERNAME);

    private saveUser(res): void {
        localStorage.setItem(this.CAH_TOKEN, res.data.token);
        localStorage.setItem(this.CAH_USERNAME, res.data.username);
        this.logger.next(true);
    }

    private deleteUser(): void {
        localStorage.removeItem(this.CAH_TOKEN);
        localStorage.removeItem(this.CAH_USERNAME);
        this.logger.next(false);
    }

    private isUserLoggedIn(): boolean {
        const user = isPlatformBrowser(this.platformId) && localStorage.getItem(this.CAH_TOKEN) ? true : false;
        return user;
    }
}

auth.api.ts

// API FOR LOGIN/LOGOUT

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../../../environments/environment';
import { Observable } from 'rxjs';

@Injectable({
    providedIn: 'root'
})
export class AuthApiService {

    constructor(private http: HttpClient) { }

    login(username: string, password: string): Observable<any> {

        const url: string = environment.cahServerUrl + 'api/users/auth/login';
        const body = { username, password };
        return this.http.post(url, body);
    }

    logout(): Observable<any> {

        const url: string = environment.cahServerUrl + 'api/users/auth/logout';
        const body = {};
        return this.http.post(url, body);
    }

}

export interface LoginRes {
    success: boolean;
    message: string;
    data: any;
}

In someComponent.ts

// WILL TELL AUTOMATICALLY WHENEVER USER LOGSIN OR LOGOUT

 this.auth.isLoggedIn().subscribe(_ => {
      this.isLoggedIn = _;
      if (_) { this.userName = this.auth.getUser().username; }
    });

In login.component.ts

// TO MAKE USER LOGIN

this.auth.login(username, password).subscribe(this.handleLogin, this.handleLoginError, () => { this.isBtnClicked = false; });


  handleLogin = (res: LoginRes) => {
    if (res.success) {
      this.router.navigate(['/']);
    }
    else {
      this.message = res.message;
    }
  }

  handleLoginError = err => {
    console.log(err);
  }

Upvotes: 0

abhay tripathi
abhay tripathi

Reputation: 4022

To persist data(user in this case) you need to save data in LocalStorage.

During Login:-

login(user: User) {
  ...
  .subscribe((data: any) => {
      localStorage.setItem('access_token', data.token)
      localStorage.setItem('currentUser', data.user)
      
  --->>>> this.currentUserSubject.next(data.user);
...
}

In Constructor:-

constructor(private httpClient: HttpClient,public router: Router) {
    this.currentUserSubject = new BehaviorSubject(localStorage.getItem('currentUser') || '');
    this.currentUser = this.currentUserSubject.asObservable();
   }

Upvotes: 1

S&#225;ndor Jankovics
S&#225;ndor Jankovics

Reputation: 898

The most simple answer is to store the value in localstorage. A little bit more harder but on a long term it pays off is the state management libraries in angular. I like to use Akita for this purpose.

Akita has the feature to store the current state in localstorage without any interaction needed even after page reload it will automatically read data from there.

Docs and source is available on github https://datorama.github.io/akita/

Upvotes: -1

Neeraj Shende
Neeraj Shende

Reputation: 358

You can not hold data in service after refresh. All the page lifecycle of the components and service runs all over again on refresh. Instead access data from localStorage/sessionStorage. So your ngOnInit will be like

const loggedInUser= (JSON.parse(localStorage.getItem('currentUser')); if(!loggedInUser) {this.currentuser = this.authService.getCurrentUser()}

Upvotes: 3

Related Questions