Redirect to a different component inside @CanActivate in Angular2

前端 未结 6 498
攒了一身酷
攒了一身酷 2020-12-03 10:03

Is there any way we can redirect to a different component from @CanActivate in Angular2 ?

相关标签:
6条回答
  • 2020-12-03 10:24

    As of today, with latest @angular/router 3.0.0-rc.1, here are a couple of references on how to do that through CanActivate guards on routes:

    1. angular 2 reference
    2. Two answers to this SO question, by Nilz11 and by Jason

    The main gist of logic looks like:

    // ...
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
      if (this.authService.isLoggedIn) {
        // all ok, proceed navigation to routed component
        return true;
      }
      else {
        // start a new navigation to redirect to login page
        this.router.navigate(['/login']);
        // abort current navigation
        return false;
      }
    }
    
    0 讨论(0)
  • 2020-12-03 10:24

    This might help someone who is trying to wait on something before continuing.

    waitForBonusToLoad(): Observable<[boolean, string]> {
    
    const userClassBonusLoaded$ = this.store.select(fromRoot.getUserClasssBonusLoaded);
    const userClassSelected$ = this.store.select(fromRoot.getClassAttendancesSelectedId);
    
    return userClassBonusLoaded$.withLatestFrom(userClassSelected$)
      .do(([val, val2]) => {
        if (val === null && val2 !== null) {
          this.store.dispatch(new userClassBonus.LoadAction(val2));
        }
      })
      .filter(([val, val2]) => {
        if(val === null && val2 === null) return true;
        else return val;
      })
      .map(val => {
        return val;
      })
      .take(1);
    }
    
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.waitForBonusToLoad().map(([val, val2]) =>
      {
        if(val === null && val2 === null){
          this.router.navigate(['/portal/user-bio']);
          return false;
        }
        else {
          return true;
        }
      }
    )
    }
    
    0 讨论(0)
  • 2020-12-03 10:28

    If you are using an observable to determine, you can leverage tap operator from rxjs:

    @Injectable({
      providedIn: SharedModule // or whatever is the equivalent in your app
    })
    export class AuthGuard implements CanActivate {
    
      constructor(private authService: AuthService,
                  private router: Router) {}
    
      canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
        return this.authService.isLoggedIn()
          .pipe(tap((isLoggedIn: boolean) => {
            if (!isLoggedIn) {
              this.router.navigate(['/']);
            }
          }));
      }
    
    }
    
    0 讨论(0)
  • 2020-12-03 10:29

    Yes, you can! Doing this will prevent your component from instantiating for nothing.

    First, make a new file src/app-injector.ts

    let appInjectorRef;
    
    export const appInjector:any = (injector = false) => {
        if (!injector) {
            return appInjectorRef;
        }
    
        appInjectorRef = injector;
    
        return appInjectorRef;
    };
    

    Then, get the reference from bootstrap

    // ...
    import {appInjector} from './app-injector';
    // ...
    
    
    bootstrap(App, [
      ROUTER_PROVIDERS
    ]).then((appRef) => appInjector(appRef.injector));
    

    Finally in your function

    // ...
    import {appInjector} from './app-injector';
    // ...
    
    @CanActivate((next, prev) => {
      let injector = appInjector();
      let router = injector.get(Router);
    
      if (42 != 4 + 2) {
        router.navigate(['You', 'Shall', 'Not', 'Pass']);
        return false;
      }
    
      return true;
    })
    

    Et voilà !

    It was discussed here https://github.com/angular/angular/issues/4112

    You can find a complete example here http://plnkr.co/edit/siMNH53PCuvUBRLk6suc?p=preview by @brandonroberts

    0 讨论(0)
  • 2020-12-03 10:30

    Your guard can easily just be an injectable which, as such, can include its own injectables. So we can simply inject the router, in order to redirect. Don't forget to add the service as a provider in your app module.

    @Injectable()
    export class AuthGuard implements CanActivate {
    
      constructor(private router: Router, private authService: AuthService) {}
    
      canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
        if (!authService.isAuthenticated()) {
          this.router.navigate(['/login']);
          return false;
        }
        return true;
      }
    }
    
    export const ROUTES: Routes = [
      {path: 'login', component: LoginComponent},
      {path: 'protected', loadChildren: 'DashboardComponent', canActivate: [AuthGuard]}
    ];
    
    0 讨论(0)
  • 2020-12-03 10:33

    As of Angular 7.1, you can return UrlTree instead of boolean:

    @Injectable({
      providedIn: 'root',
    })
    export class AuthGuard implements CanActivate {
    
      constructor(private authService: AuthService, private router: Router) { }
    
      canActivate(): boolean | UrlTree {
        return this.authService.isAuthenticated() || this.router.createUrlTree(['/login']);
      }
    }
    
    0 讨论(0)
提交回复
热议问题