akuma8
akuma8

Reputation: 4691

How to use NgRx Store in a Router Guard?

Similar questions have been asked but none solution worked for me. The state of my Store is:

export interface AuthState {
  isLoggedIn: boolean,
  ...
}

I would like to use that isLoggedIn in the router guard so I have something like this:

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {

  constructor(private router: Router,
              private store: Store<fromAuth.AuthState>) {
  }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    return this.canNavigate();
  }

  canNavigate(): Observable<boolean> {
    return this.store.select(AuthSelectors.selectIsLoggedIn).pipe(
      filter(isLoggedin => isLoggedin), // issue comes from here
      tap(isLoggedId => {
        if (!isLoggedId) {
          this.router.navigateByUrl('/login').then()
        }
      })
    );
  }
}

This code works well when a user just logged in but not work when we reload the application and don't have a token locally. After reloading the app, I have a blank page because the filter() method is stuck.

I implemented an autoLogin() method which dispatch an action to set the isLoggedIn to true in the store when we reload the app, it works but same problem when there isn't a token. The question is how to by-pass the filter() and redirect to the login page when we isLoggedIn is false?

EDIT

This is the code of the autoLogin() method:

autoLogin() {
 from(getTokenFromLocalStorage()).pipe(
  tap(token => {
    if (token) {
        this.store.dispatch(AuthActions.autoLogin({payload: token}));
     }
   })
).subscribe();

}

Then in the reducer I update the isLoggedIn field. autoLogin() is used in the AppComponent:

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent implements OnInit {
  constructor(private authenticationService: AuthenticationService) {}

  ngOnInit() {
    console.log("App start");
    this.authenticationService.autoLogin();
  }
}

@brunoj's answer suggests to remove the filter() function, I can't do it because the AuthGuard#canActivate() method is executed before the reducer, so before the update of the isLoggedIn field. filter() permits the waiting for the update in the reducer.

Upvotes: 0

Views: 1075

Answers (1)

brunoj
brunoj

Reputation: 66

Like DeborahK said filter operator is filtering every isLoggedin falsy value. You jusst need to remove filter operator from your stream. When your stream will have false value navigation will be canceled and your tap operator will be executed and user will be redirected to login page.

Upvotes: 1

Related Questions