Jamie Bohanna
Jamie Bohanna

Reputation: 560

Angular Router redirecting back to base route on from certain routes, but fixes itself when you refresh the page

For some strange reason, only for certain routes, Angular Router is redirecting the user back to the base url.

Sounds like a problem with my app-routing.module.ts right?

Well this is where the strange issues start.

Strange Issue #1

Only happens when trying to navigate to /leaderboard and to /achievements but not on /team-view

Strange Issue #2

If I make a change to the code OR simply refresh the page, the problems are now resolved and I can now reach both /leaderboard and /achievements without any problems. If I log out and log back in, the problem returns.

Strange Issue #3

There are no console errors or any form of error aside from the page just flickering very quickly and redirecting me back to the / route (which is the Dashboard Component loads`)

Routes:

const routes: Routes = [
    {
        path: '',
        pathMatch: 'full',
        component: DashboardComponent,
        canActivate: [LoggedInGuard],
    },
    {
        path: 'team-view',
        component: TeamViewComponent,
        canActivate: [LoggedInGuard],
    },
    {
        path: 'settings',
        component: SettingsComponent,
        canActivate: [LoggedInGuard],
    },
    {
        path: 'leaderboard',
        component: LeaderboardComponent,
        canActivate: [LoggedInGuard],
    },
    {
        path: 'achievements',
        component: AchievementsComponent,
        canActivate: [LoggedInGuard],
    },
    { path: 'register', component: RegisterComponent },
    { path: 'login', component: LoginComponent },
];

Header Code:

<div class="menu-wrapper desktop-menu">
    <span class="menu-item" routerLinkActive="menu-item-active" [routerLinkActiveOptions]="{ exact: true }" routerLink="/">Dashboard</span>
    <span class="menu-item" routerLinkActive="menu-item-active" [routerLinkActiveOptions]="{ exact: true }" routerLink="/leaderboard">Leaderboard</span>
    <span class="menu-item" routerLinkActive="menu-item-active" [routerLinkActiveOptions]="{ exact: true }" routerLink="/achievements">Achievements</span>
    <span class="menu-item" routerLinkActive="menu-item-active" [routerLinkActiveOptions]="{ exact: true }" routerLink="/team-view">My Team</span>
    <span class="menu-item" routerLinkActive="menu-item-active" (click)="ToggleNotifications()"><mat-icon matBadge="4">notifications</mat-icon></span>
    <span class="menu-item" routerLinkActive="menu-item-active" (click)="SignOut()"><mat-icon>logout</mat-icon></span>
</div>

LoggedInGuard:

@Injectable()
export class LoggedInGuard implements CanActivate {
    constructor(private router: Router) {}

    canActivate(): Observable<boolean> | Promise<boolean> | boolean {
        const isLoggedIn = localStorage.getItem('jwt') !== null;

        if (!isLoggedIn) {
            console.log('Returning to login screen');
            this.router.navigateByUrl('login');
        }

        return isLoggedIn;
    }
}

I also noticed some weird logging in the Angular Routing that seems to indicate that Angular Router is forcing a redirect but I don't know why?:

GuardsCheckEnd(id: 11, url: '/', urlAfterRedirects: '/', state: Route(url:'', path:'') { Route(url:'', path:'') } , shouldActivate: true)

Upvotes: 4

Views: 5257

Answers (4)

H. B. Young
H. B. Young

Reputation: 11

This is really more appropriate as a comment, but when I've seen flickering in a front end app like that it was due to one of two things:

  1. Some member of the app or component state that influences the rendering is updating before the page can finish loading ( page starts to load -> hook updates state -> page starts rendering -> state updates before rendering completes -> page starts rendering over again)
  2. Something is triggering a cascade of redirects internally

I know it's not much of an answer, but I would recommend double checking the leaderboard and achievements components. If possible maybe add a log statement detailing component state. Any shared logic or sub-components seem like a good candidate for debugging.

If you haven't all ready, try opening dev tools and monitoring the network tab just to rule out the redirect option.

Upvotes: 1

Joosep Parts
Joosep Parts

Reputation: 6225

What happens with your jwt token after you refresh? Maybe you lose jwt during some process?

But from your description seems like CanActivate kicks in forces you to login where, perhaps, we find that user is logged in and login component by default moves you to /.

canActivate should always return boolean true/false, but here we just naviage user away:

        if (!isLoggedIn) {
            console.log('Returning to login screen');
            this.router.navigateByUrl('login');
        }
@Injectable()
export class LoggedInGuard implements CanActivate {
    constructor(private router: Router) {}

    canActivate(): Observable<boolean> | Promise<boolean> | boolean {
        const isLoggedIn = localStorage.getItem('jwt') !== null;

        if (!isLoggedIn) {
            console.log('Returning to login screen');
            this.router.navigateByUrl('login');
            return false;
        } else {
           return true;        
        }

    }
}

Upvotes: 0

paranaaan
paranaaan

Reputation: 1735

Put this in app-routing.module.ts

imports: [
    RouterModule.forRoot(
      routes,
      { enableTracing: true }
    )
]

The application will log out route behavior so you can investigate the issue.

For me, I think the problem is around Strange Issue #1, it can be cause by router function. Actions of router.navigate and router.navigateByUrl weren't be all the same.

Upvotes: 1

The Fabio
The Fabio

Reputation: 6240

You should not use pathMatch: 'full' everywhere, it does not play well (especially if you have nested routes). The docs give you examples of the most common usages. It is usually a good idea to redirect empty string routes to avoid other issues.

Something like this should work:

const routes: Routes = [
        {
            path: '',
            pathMatch: 'full',
            redirectTo: 'dashboard',
        },
        {
            path: 'dashboard',
            component: DashboardComponent,
            canActivate: [LoggedInGuard],
        },
        {
            path: 'team-view',
            component: TeamViewComponent,
            canActivate: [LoggedInGuard],
        },
        {
            path: 'settings',
            component: SettingsComponent,
            canActivate: [LoggedInGuard],
        },
        {
            path: 'leaderboard',
            component: LeaderboardComponent,
            canActivate: [LoggedInGuard],
        },
        {
            path: 'achievements',
            component: AchievementsComponent,
            canActivate: [LoggedInGuard],
        },
        { path: 'register', component: RegisterComponent },
        { path: 'login', component: LoginComponent },
    ];

Upvotes: 0

Related Questions