Web Develop Wolf
Web Develop Wolf

Reputation: 6316

Subscribe Execution Order in Angular

I'm attempting to validate if a user is logged in or not as soon as they load the page, but the execution order of the code is making this extremely difficult. Here's the code that checks if the user is logged in:

ngOnInit() {
    this.authService.authState.subscribe((user) => {
      this.user = user;
      this.loggedIn = (this.user != null);
      this.getUserProfile(user);
      console.log(this.loggedIn);
    });
    console.log(this.loggedIn);
    if (this.loggedIn) {
      console.log("Don't Redirect")
    } else {
      console.log("Redirect");
    }
  }

When running this code, this code block executes first:

console.log(this.loggedIn);
    if (this.loggedIn) {
      console.log("Don't Redirect")
    } else {
      console.log("Redirect");
    }

Then if the user is logged in this block will execute second:

this.authService.authState.subscribe((user) => {
      this.user = user;
      this.loggedIn = (this.user != null);
      this.getUserProfile(user);
      console.log(this.loggedIn);
    });

If the user is not logged in then the code in the subscribe does not execute at all, so I'm having trouble working out how I can redirect users away from the page to the login if they are logged out and keep them where they are and get the user profile if they are logged in. Maybe I've just been staring at it for so long now I just can't get my head round it, but either way can anyone help?

Upvotes: 1

Views: 696

Answers (1)

AVJT82
AVJT82

Reputation: 73357

UPDATE:

Since we found out that you want to prevent user accessing a route if not logged in, I suggest using a route guard.

Also if you want to persist the user on page refresh, you need to use something like localStorage

So when you log in, set user to localstorage:

this.authService.authState.subscribe((user) => {
  this.user = user;
  localStorage.setItem('user', this.user)
});

To grab the user when you need it, use:

this.user = localStorage.getItem('user');

When the user logs out, use either clear() or removeItem:

localStorage.removeItem('user');

Now you have access to the user whenever you need it. Though, in this case, use a route guard to protect your route. Follow the steps in the docs

and this is then how your guard would look like:

export class AuthGuard implements CanActivate {
  constructor(private router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean {
    let url: string = state.url;

    return this.checkLogin(url);
  }

  checkLogin(url: string): boolean {
    const user = localStorage.getItem('user');
    if (user) {
      return true;
    }
    // route where you want to route and return false
    this.router.navigate(['/login']);
    return false;
  }
}

Now with this, you don't even need the check in the component, so remove this:

if (this.loggedIn) {
  console.log("Don't Redirect")
} else {
  console.log("Redirect");
}

... since the guard now takes care of this!

As a last comment, you could also look into state management, for example with ngrx-store, there is a plugin which also connects localStorage to that.


ORIGINAL ANSWER:

Reading up on the plugin, indeed you are only notified when user has logged in or logged out, nothing in between. I guess you could leverage your own variable/Behaviorsubject. I like BehaviorSubject ;)

So in a service, here called MyService:

private appUser = new BehaviorSubject(null);
public appUser$ = this.appUser.asObservable();

modifyStatus(appUser: any) {
  this.appUser.next(appUser);
}

Then, where you are logging in user, add in the callback:

this.authService.authState.subscribe((user) => {
    this.user = user;
    this.myService.modifyStatus(user);
});

And when logges out, you again just call this.myService.modifyStatus(null).

In your component you can then subscribe to that...

this.myService.appUser$.subscribe((user: any) => {
  if (user) {
    console.log("Don't Redirect")
  } else {
    console.log("Redirect");
  }
});

Upvotes: 3

Related Questions