Angular data loss on reload using BehaviorSubject
Asked Answered
A

2

11

I'm using a data service to send the user data to the app and display the username in my header component. If I sign in in my app with login component the username is correctly displayed, but when I reload the page the user data disappears.

on login Before reload

enter image description here enter image description here

after reload

enter image description here enter image description here

the user data comes from a data service that use a BehaviorSubject:

data.service.ts

    export class DataService {
    
      private userSource = new BehaviorSubject({});
      currentUser = this.userSource.asObservable().pipe(distinctUntilChanged());
    
      constructor(private injector: Injector, private api: UtentiApiService) { }
    
      getUser() {
        return this.currentUser;
      }
    
      getUserFromToken() {
        const authService = this.injector.get(AuthService);
        const token = authService.getToken();
        const userIdToken = jwt_decode(token);
        // console.log(userIdToken);
        return this.api.getUtente(userIdToken.userId);
      }
    
      getPermissionsFromToken(): Observable<any> {
        const authService = this.injector.get(AuthService);
        const token = authService.getToken();
        const userIdToken = jwt_decode(token);
    
        return of(userIdToken.permArr);
      }
      changeUser(user: object) {
        this.userSource.next(user);
      }
    
    }

in header component I consume the service:

header.component.ts

    export class HeaderComponent implements OnInit {
      user: object;
    
      constructor(private router: Router, private authService: AuthService, private data: DataService) { }
    
    
      ngOnInit() {
        this.getUser();
      }
    
      getUser() {
        this.data.getUser().subscribe(utente => {
          this.user = utente;
          console.log(this.user);
        });
      }
    
      onLogout() {
        this.authService.logoutUser();
      }
    
      sendUser(user) {
        this.data.changeUser(user);
      }
    }

in the login component I send the user data to the data service, but on reload the login component is not fired, so I have no user data in the service nor in the header. How can I fix this bug?

Here a stackblitz with the full code: https://stackblitz.com/github/ufollettu/SEANSA

Thank you for help

Acronym answered 8/8, 2018 at 9:23 Comment(1)
Isn't this exactly why we have a concept of session management? So basically on login you have to store the data in the localStorage. On component init, you check if there is userData in localStorage, the use that. Otherwise navigate the user back to login componentBucci
E
9

Use SessionStorage or localStorage or cookies to store your data.

When you hit refresh copy your data in any of the above storage and on init copy it back into your variable. Check below example. Replace the sessionStorage to localStorage to store data in localStorage.

In AppComponent

    ngOnInit() {
    if (sessionStorage.getItem("user")) {
      this.data.changeUser(sessionStorage.getItem("user"));
    }
      }
@HostListener('window:beforeunload', ['$event'])
      unloadNotification($event: any) {
        sessionStorage.setItem("user", this.getUser());
      }
Expectancy answered 8/8, 2018 at 10:31 Comment(0)
H
6

From your code:

private userSource = new BehaviorSubject({});
  currentUser = this.userSource.asObservable().pipe(distinctUntilChanged());

  constructor(private injector: Injector, private api: UtentiApiService) { }

  getUser() {
    return this.currentUser;
  }

Your userSource is a BehaviorSubject which contains nothing when you start your application (also on reload).

When you login a user you call:

changeUser(user: object) {
    this.userSource.next(user);
  }

After this call your BehavoirSubject contains a user. But you only do this during login process.

When you reload your page you need to fetch the access token from localstorage, and call next on the BehavoirSubject with the current user.

You can do that in the constructor of the dataService for instance.

Haslet answered 8/8, 2018 at 9:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.