2

I'm doing an Angular application with the following routing:

const routes: Routes = [
  {
    path: '',
    component: LoginLayoutComponent,
    children: [
      {
        path: '',
        redirectTo: 'login',
        pathMatch: 'full'
      },
      {
        path: 'login',
        component: LoginComponent
      }
    ]
  },
  {
    path: '',
    component: HomeLayoutComponent,
    canActivate: [AuthGuardService],
    children: [
      {
        path: 'users',
        component: UsersComponent,
      },
      {
        path: 'detail/:id',
        component: UserComponent,
      },
      {
        path: 'dashboard',
        component: DashboardComponent,
        data: {
          expectedRole: 'admin'
        }
      },
      {
        path: 'home',
        loadChildren: './views/home/home.module#HomeModule',
        data: {
          preload: true,
          delay: false
        }
      },
      {
        path: 'error',
        component: ErrorComponent
      },
    ]
  },
];

If I'm not logged in and I request any secured url, like for example http://localhost:4200/users or http://localhost:4200/dashboard then there is a redirect to the http://localhost:4200/ and the application goes into an infinite loop. If I'm logged in then it works fine.

The browser console displays the following message Navigation triggered outside Angular zone.

Here is my auth guard service:

  canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
    const expectedRole = route.data.expectedRole ? route.data.expectedRole : null;
    const tokenPayload = this.tokenService.getDecodedAccessToken();
    return this.authService.isAuthenticated()
    .pipe(
      map(isAuth => {
        if (!isAuth) {
          this.router.navigate(['login']);
          return false;
        } else {
          return true;
        }
      }),
      catchError((error, caught) => {
        return of(false);
      })
    );
  }

  canLoad(): Observable<boolean> {
    if (this.authService.isAuthenticated()) {
      return of(true);
    } else {
      return of(false);
    }
  }

I'm on Angular 7

EDIT: The issue is now resolved with the following auth guard:

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.authService.isAuthenticated()
    .pipe(
      map(isAuthenticated => {
        if (!isAuthenticated) {
          this.authService.setPostLoginRedirectUrl(state.url);
          this.router.navigate(['login']);
          return false;
        } else {
          return true;
        }
      }),
      catchError((error, caught) => {
        return of(false);
      })
    );
  }

and the following routes:

const routes: Routes = [
  {
    path: '',
    component: LoginLayoutComponent,
    children: [
      {
        path: '',
        redirectTo: 'login',
        pathMatch: 'full'
      },
      {
        path: 'login',
        component: LoginComponent
      }
    ]
  },
  {
    path: '',
    component: HomeLayoutComponent,
    canActivateChild: [AuthGuardService],
    children: [
      {
        path: 'users',
        component: UsersComponent,
      },
      {
        path: 'detail/:id',
        component: UserComponent,
      },
      {
        path: 'dashboard',
        component: DashboardComponent,
        data: {
          expectedRole: 'admin'
        }
      },
      {
        path: 'home',
        loadChildren: './views/home/home.module#HomeModule',
        data: {
          preload: true,
          delay: false
        }
      },
      {
        path: 'error',
        component: ErrorComponent
      },
    ]
  },
];
Stephane
  • 11,836
  • 25
  • 112
  • 175

5 Answers5

1

EDIT: Found out the culprit! In app.module.ts you need to import AuthModule first. Doing this will allow you to use the path '**' in either 'auth-routing.module.ts' or 'app-routing.module.ts'

@NgModule({

  imports: [
    AuthModule,
    AppRoutingModule,
    BrowserModule,
    HttpClientModule,
    SharedModule
  ],
})

I was having an infinite loop issue as well. Not sure if this relates to yours but for me I had two routing files. 'app-routing.module.ts' and 'auth-routing.module.ts'. I moved the code below from ' app-routing.module.ts' into 'auth-routing.module.ts' and no more infinite loops! Hope this helps you in some way!

 {
    path: '**',
    redirectTo: 'my-route',
  }
Melissa Heying
  • 1,302
  • 1
  • 4
  • 4
0

redirectTo value should always have a leading / as it represents the actual route the user should be navigated to.

Change redirectTo: 'login', to redirectTo: '/login', in your Route Config

Also, this:

this.router.navigate(['login']);

should be

this.router.navigate(['/login']);
SiddAjmera
  • 38,129
  • 5
  • 72
  • 110
0

I don't have an exact soution for you, just a few this suggestions for debugging. Try expressing this as:

const routes: Routes = [
{
  path: '',
  component: LoginLayoutComponent,
  children: [
    {
      path: 'login',
      component: LoginComponent
    },
    {
      path: '',
      component: LoginComponent,
      pathMatch: 'full'
    },
  ]
}

to see if it is the route redirect.

Try replacing this with,

this.router.navigateByUrl('/login');

or

this.router.navigate(['', 'login']);
Avin Kavish
  • 8,317
  • 1
  • 21
  • 36
0

For my problem, the order of import impacts on this error.

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    CommonModule,

    AccountModule, // Load other eager modules first
    AppRoutingModule // Move this AppRouting to the end like this
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}
Steve Lam
  • 979
  • 1
  • 17
  • 40
0

In my case (topic is similar) when I was getting loop it was AuthGuard on Login route.

{ path: 'login', component: LoginFormComponent, canActivate: [AuthGuard], }

To fix this I just removed guard from Login route.

Marian Turchyn
  • 519
  • 5
  • 6