14

I have the following routes defined:

export const routes: Routes = [
    { path: '', component: HomeComponent, pathMatch: 'full', canActivate: [AuthGuardService] },
    { path: 'sites', component: SiteIndexComponent, resolve: { siteSummaries: SiteSummariesResolve }, canActivate: [AuthGuardService] },
    { path: 'qa-tasks', component: QaTaskIndexComponent, resolve: { investigations: InvestigationsResolve, reviews: ReviewsResolve }, canActivate: [AuthGuardService] },
    { path: 'error', component: ErrorComponent },
    { path: '**', redirectTo: '' }
];

Users of my app see totally different pages based on their role including their "landing" (home) page. I'm using my HomeComponent to route the user to the correct landing page based on role like this:

export class HomeComponent implements OnInit {

    private roles: any;

    constructor(private router: Router,
        private authService: AuthService) { }

    ngOnInit() {
        var currentUser = this.authService.getCurrentUser();
        this.roles = currentUser.roles;
        this.redirect();
    }

    private redirect() {
        var route;
        if (this.inRole('site-user-role')) {
            route = 'sites';
        }
        else if (this.inRole('qa-user-role')) {
            route = 'qa-tasks';
        }
        if (route) {
            this.router.navigate([route]);
        }
        else {
            this.router.navigate(['error']);
        }
    }

    private inRole(role) {
        return _.includes(this.roles, role);
    }
}

When the HomeComponent is first loaded after login, the route does not navigate to, for example, the 'sites' route, but strangely it resolves the siteSummaries dependency. After the first time it fails to redirect, I can navigate to another route and then try to navigate to the '' route and it correctly redirects to the 'sites' route.

Why is the initial navigation not working? Based on other similar questions about navigate() not working, I've tried changing my route to '/sites' and './sites', but to no avail.

Update It looks like it has to do with resolving a dependency for a route. If redirect to the 'error' route in my redirect() function, it does it successfully the first time. If I add a resolve to my 'error' route, it fails to navigate to it the first time. The odd thing is it makes the HTTP call to fulfill the dependency. Is this an issue with it not awaiting the return of navigate()'s promise?

Update 2 Here are the requested classes:

export class SiteIndexComponent implements OnInit {

    public siteSummaries: any;
    public totalRegisteredCount: number;
    public totalscreenFailedCount: number;
    public totalinProgressCount: number;

    constructor(private route: ActivatedRoute) { }

    ngOnInit() {
        this.siteSummaries = this.route.snapshot.data['siteSummaries'];
        this.totalRegisteredCount = this.getTotal('registeredCount');
        this.totalscreenFailedCount = this.getTotal('screenFailedCount');
        this.totalinProgressCount = this.getTotal('inProgressCount');
    }

    private getTotal(prop): number {
        var total = 0;
        _.forEach(this.siteSummaries, function (summary) {
            return total += summary[prop];
        });
        return total;
    }
}

@Injectable()
export class SiteSummariesResolve implements Resolve<any> {

    constructor(private sitesService: SitesService) { }

    resolve(route: ActivatedRouteSnapshot) {
        return this.sitesService.getSiteSummaries();
    }
}

getCurrentUser(): any {
    var currentUser = sessionStorage.getItem('currentUser');
    if (!currentUser) {
        return null;
    }
    return JSON.parse(currentUser);
}

Update 3 I threw this into my app.component:

private navigationInterceptor(event: RouterEvent): void {
    if (event instanceof NavigationStart) {
        console.log('started: ' + JSON.stringify(event));
    }
    if (event instanceof NavigationEnd) {
        console.log('ended: ' + JSON.stringify(event));
    }
    if (event instanceof NavigationCancel) {
        console.log('cancelled:' + JSON.stringify(event));
    }
    if (event instanceof NavigationError) {
        console.log('error:' + JSON.stringify(event));
    }
}

On the times when it fails to load the route (the first time), there is first an event instance of NavigationStart and then an instance of NavigationCancel. Here is what event looks like on the NavigationCancel: {"id":2,"url":"/sites","reason":""}. As you can see, no reason is given...

mellis481
  • 4,332
  • 12
  • 71
  • 118

3 Answers3

10

I still don't know why it was cancelling my route navigation, but a work around I've come up with is to change ngInit to the following:

ngOnInit() {
    var currentUser = this.authService.getCurrentUser();
    this.roles = currentUser.roles;
    var that = this;
    setTimeout(function () { that.redirect(); }, 50);
}

Wrapping my redirect call in a timeout allows things to work as expected with the exception of a imperceptible delay. It would seem it's some sort of timing issue? If I try setting the timeout to 20 it also doesn't work.

mellis481
  • 4,332
  • 12
  • 71
  • 118
  • With this method I get `ERROR TypeError: this.redirect is not a function` even though I defined it and use it like this : `private redirect(path: string): void` – An-droid Aug 09 '17 at 12:31
  • @An-droid note the `that = this` – BeaverusIV Aug 15 '17 at 02:37
  • This setTimeout work-around worked for me when trying to navigate inside an ```CustomErrorHandler```... – jonas Oct 12 '17 at 10:08
  • I was having the same issue. I wrote a custom resolver that converts incoming hash to path and the redirect was firing consistently on all but one of the paths. I'd concur that it's probably some screwy timing issue. If router.navigate somehow gets intercepted because it's taking too long to fire, setTimeout will push it onto the event queue to fire asynchronously. – Evan Plaice Dec 15 '17 at 06:07
0

You should not do things with side effects in the constructor. Instead, implement ngOnInit:

class HomeComponent implements OnInit {
  ngOnInit() {
    // navigate things...
  }
}

See also: Difference between Constructor and ngOnInit

Community
  • 1
  • 1
Tatsuyuki Ishi
  • 3,883
  • 3
  • 29
  • 41
-1

try this for routing

import { Routes, RouterModule } from '@angular/router';


export const router: Routes = [
   { path: '',  redirectTo: 'main', pathMatch: 'full'},
  { path: 'main', component:AdminBodyComponent  },
  { path: 'admin', component:AdminComponent  },
  { path: 'posts',component:PostsComponent},
  { path: 'addposts',component:AddPostComponent}];

export const routes: ModuleWithProviders = RouterModule.forRoot(router);
step2:
inject into your .ts file
constructor(
  private router:Router,
  ...
)
step3:
this.router.navigate(['/addposts']);
Always Learn
  • 662
  • 6
  • 14