最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - redirectTo not working when using canActivate guard - Stack Overflow

programmeradmin0浏览0评论

The redirectTo property isn't working in my Angular 2 app. I have the following routes in my app.routing.ts:

const routes: Routes = [
  { path: '', redirectTo: '/page/1', pathMatch: 'full' },
  { path: 'page', loadChildren: 'app/modules/page/page.module#PageModule' }
]

export const routing = RouterModule.forRoot(routes);

Then, in my page.routing.ts, I have the following:

const pageRoutes: Routes = [
  { path: ':id', ponent: PageComponent, canActivate: [LoginGuard] }
];

export const pageRouting = RouterModule.forChild(pageRoutes);

Every time I access the home page it displays the LoginComponent for a second, then it disappears. However, it should redirect to the PageComponent.

Why isn't that happening? Why the LoginComponent is being loaded (even if it's only for a brief second) if the user is already logged in?

Here's my LoginGuard:

@Injectable()
export class LoginGuard implements CanActivate {

  constructor(private af: AngularFire, private router: Router) {}

  canActivate(): Observable<boolean> {
    return this.af.auth.map(auth =>  {
      if (auth === null) {
        this.router.navigate(['/login']);
        return false;
      } else {
        return true;
      }
    }).first();
  }

}

EDIT: Temporarily, I changed the LoginComponent to redirect to the PageComponent if a user is logged in. I still wonder, though, why redirectTo isn't working.

The redirectTo property isn't working in my Angular 2 app. I have the following routes in my app.routing.ts:

const routes: Routes = [
  { path: '', redirectTo: '/page/1', pathMatch: 'full' },
  { path: 'page', loadChildren: 'app/modules/page/page.module#PageModule' }
]

export const routing = RouterModule.forRoot(routes);

Then, in my page.routing.ts, I have the following:

const pageRoutes: Routes = [
  { path: ':id', ponent: PageComponent, canActivate: [LoginGuard] }
];

export const pageRouting = RouterModule.forChild(pageRoutes);

Every time I access the home page it displays the LoginComponent for a second, then it disappears. However, it should redirect to the PageComponent.

Why isn't that happening? Why the LoginComponent is being loaded (even if it's only for a brief second) if the user is already logged in?

Here's my LoginGuard:

@Injectable()
export class LoginGuard implements CanActivate {

  constructor(private af: AngularFire, private router: Router) {}

  canActivate(): Observable<boolean> {
    return this.af.auth.map(auth =>  {
      if (auth === null) {
        this.router.navigate(['/login']);
        return false;
      } else {
        return true;
      }
    }).first();
  }

}

EDIT: Temporarily, I changed the LoginComponent to redirect to the PageComponent if a user is logged in. I still wonder, though, why redirectTo isn't working.

Share edited Oct 31, 2016 at 0:21 brians69 asked Oct 30, 2016 at 23:52 brians69brians69 4853 gold badges12 silver badges26 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 2

You should NOT navigate inside a Guard

This is happening because you call this.router.navigate(['/login']); directly from your route guard which initializes a new route navigation on top of the one currently running. You create a "race" between two navigations; my guess is the one to /login' wins because the other one has to lazy load the module (takes some time). But after the loading is done, it changes to that route afterwards, hence the "flashing" login popup.

You should NOT navigate inside a Guard, instead you should always return either a boolean (to allow navigate true/false) or a UrlTree if you want to redirect/change the route. The Guard returns the value and the router will then change navigation to the provided UrlTree for you inside the ongoing/triggered navigation and you won't get any race.

So change your method like this, and it will work correct.

canActivate(): Observable<boolean|UrlTree> {
  return this.af.auth.map(auth =>  {
    if (auth === null) {
      return this.router.parseUrl('/login');
    }
    return true;
  }).first();
}

You should see it like this, if you would call this.router.navigate in several route guards then the router wouldn't know where to navigate to, by returnin a UrlTree this problem is resolved. See also a related question/answer here

I don't know exactly why this is happening, but I believe if you check the LoginGuard before the PageModule loads, it will work.

app.routing.ts

const routes: Routes = [
  { path: '', redirectTo: '/page/1', pathMatch: 'full' },
  { 
    path: 'page', 
    // Call the guard before the module is loaded
    canLoad: [ LoginGuard ]
    loadChildren: 'app/modules/page/page.module#PageModule' 
  }
]

export const routing = RouterModule.forRoot(routes);

LoginGuard

@Injectable()
export class LoginGuard implements CanActivate, CanLoad {

  constructor(private af: AngularFire, private router: Router) {}

  // Add this method to validade the canLoad
  canLoad(route: Route): Observable<boolean> {
    return this.canActivate();
  }  

  canActivate(): Observable<boolean> {
    return this.af.auth.map(auth =>  {
      if (auth === null) {
        this.router.navigate(['/login']);
        return false;
      } else {
        return true;
      }
    }).first();
  }

}
发布评论

评论列表(0)

  1. 暂无评论