'Angular 2: How to redirect route to child route with named outlet

I´m having a problem with Angular 2 router. I cannot get it to redirect to a specific child route with a named outlet. I think it´s a problem of URL encoding. I hope someone can help me. This is my routes setup:

const appRoutes: Routes = [
  { 
    path: 'browse',                
    component: BrowseComponent, 
    children: [
      { 
        path: 'first', 
        component: BrowseFirstComponent,
        outlet: 'view'
      },
      { 
        path: 'second', 
        component: BrowseSecondComponent,
        outlet: 'view'
      },
      { 
        path: 'third', 
        component: BrowseThirdComponent, 
        outlet: 'view'
      },
    ] 
  },
  { path: 'search', component: SearchComponent },
  { path: '',       redirectTo: '/browse/(view:first)', pathMatch: 'full' },
];

If I navigate to http://mysrv/browse/(view:first) manually (per typing in the url), it works fine. But if I naviagte to http://mysrv/ instead the router tries to redirect me to 'browse/(view%3Afirst)' which does not work:

EXCEPTION: Uncaught (in promise): Error: Cannot match any routes: 'browse/(view%3Afirst)'

I´m using Angular 2.0.0 and router Package 3.0.0

Can somebody help me please?



Solution 1:[1]

You need to update to a more recent Angular2 and Router version.

This is a known issue that is fixed since about 2 weeks.

https://github.com/angular/angular/issues/12740

Solution 2:[2]

For anybody finding issues with redirectTo and named outlets, and stumbling on this issue. This ticket has been open since 2017 and addresses redirectTo for child routes and named outlets.

Basically, if you want your main component to redirect to the one of the children, you have 2 choices.

1) need to fill in an absolute, full path in for 'redirectTo':

https://github.com/angular/angular/issues/18271

2) if you can't do that (eg. your route is nested containing a wildcard like ':id'), you can perform a redirect via a Guard or in that parent component itself. Basically, you catch the ActivatedRouteSnapshot to see if you are on the parent itself or one of the children (you know you're on the parent if the nested 'children' array is empty) + you catch RouterStateSnapshot to see what url you are on) and then perform a 'navigateByUrl' to the url of the child you need.

canActivateChild(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean>|Promise<boolean>|boolean {
    return this.canActivate(route, state);
}


canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {

  if (route.data.redirectToChild.length) {
    const oldUrl = state.url;

    // don't want to be on a child path already,
    // so check that:
    // - we are not already on a child route
    if (route.children.length < 1) {
      const newUrl = oldUrl + '/' +  '(my-outlet:my-child-path)';
      console.log(oldUrl);
      console.log(newUrl);
      this._router.navigateByUrl(newUrl);
    }
  }
}

Solution 3:[3]

My issue was this error 'Only absolute redirects can have named outlets.' Since the angular named outlet URL is not desired, I use a url serializer to clean those up and maintain the named outlet paths internally. I do not need or want my named outlets to persist between sessions so this is fine for my use case.

That said, I ended up using the guard to handle my redirects as angular 13 still does not allow a relative redirect when a route serializer maintains the named outlet urls.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Günter Zöchbauer
Solution 2
Solution 3 Shawn Palmer