angular: Routing: Named outlets do not work properly as child routes
I’m submitting a…
[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
Current behavior
I need 2 named outlets for my navigation. For this I followed the official angular docs example and ended up having this:
1) Works fine
RouterModule.forRoot([
{ path: 'secondPage/:id', component: SecondPageComponent, outlet: 'contentSecond' },
{ path: 'firstPage', component: FirstPageComponent, outlet: 'contentFirst' }
], { useHash: true, enableTracing: true })
Which works fine.
In my case I need to put those routes in a parent route with an Authentication Guard:
2.1) Does not work as expected
RouterModule.forRoot([
{
canActivate: [],
path: '',
children: [
{ path: 'secondPage/:id', component: SecondPageComponent, outlet: 'contentSecond' },
{ path: 'firstPage', component: FirstPageComponent, outlet: 'contentFirst' }
]
}
], { useHash: true, enableTracing: true })
// Using this to route inside the outlet
// this.router.navigate([{ outlets: { contentSecond: ['secondPage', pageNumber] } }]);
Which causes this
Router Event: NavigationStart
platform-browser.es5.js:1017 NavigationStart(id: 2, url: '/(contentSecond:secondPage/1)')
platform-browser.es5.js:1017 NavigationStart {id: 2, url: "/(contentSecond:secondPage/1)"}
platform-browser.es5.js:1026
Router Event: NavigationError
platform-browser.es5.js:1017 NavigationError(id: 2, url: '/(contentSecond:secondPage/1)', error: Error: Cannot match any routes. URL Segment: 'secondPage/1')
platform-browser.es5.js:1017 NavigationError {id: 2, url: "/(contentSecond:secondPage/1)", error: Error: Cannot match any routes. URL Segment: 'secondPage/1'
at ApplyRedirects.noMatchError (http…}
core.es5.js:1020
ERROR Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'secondPage/1'
Error: Cannot match any routes. URL Segment: 'secondPage/1'
2.2) Works but feels weird since 2.1 fails
RouterModule.forRoot([
{
canActivate: [],
path: '',
children: [
{ path: 'example', component: FirstPageComponent }
]
}
], { useHash: true, enableTracing: true })
/*
Router Event: NavigationStart
platform-browser.es5.js:1017 NavigationStart(id: 2, url: '/example')
platform-browser.es5.js:1017 NavigationStart {id: 2, url: "/example"}
platform-browser.es5.js:1026
Router Event: RoutesRecognized
platform-browser.es5.js:1017 RoutesRecognized(id: 2, url: '/example', urlAfterRedirects: '/example', state: Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'example', path:'example') } } )
platform-browser.es5.js:1017 RoutesRecognized {id: 2, url: "/example", urlAfterRedirects: "/example", state: RouterStateSnapshot}
*/
3) This works partly but fails at the end
RouterModule.forRoot([
{
canActivate: [],
path: '',
children: [
{
path: 'home', children: [{ path: 'firstPage', component: FirstPageComponent, outlet: 'contentFirst' }]
},
{
path: 'secondPage', children: [{ path: ':id', component: SecondPageComponent, outlet: 'contentSecond' }]
}
]
}
], { useHash: true, enableTracing: true })
/*
1) Works fine
this.router.navigate([
'secondPage', {
outlets: { contentSecond: [pageNumber] }
}
]);
2) Works fine
this.router.navigate([
'home', {
outlets: { contentFirst: ['firstPage'] }
}
]);
3) Fails
this.router.navigate([
'secondPage', {
outlets: { contentSecond: [pageNumber] }
}
]);
Router Event: ResolveStart
platform-browser.es5.js:1017 ResolveStart(id: 4, url: '/secondPage/(contentSecond:1)', urlAfterRedirects: '/secondPage/(contentSecond:1)', state: Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'secondPage', path:'secondPage') { Route(url:'1', path:':id') } } } )
platform-browser.es5.js:1017 ResolveStart {id: 4, url: "/secondPage/(contentSecond:1)", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.es5.js:1026
Router Event: ResolveEnd
platform-browser.es5.js:1017 ResolveEnd(id: 4, url: '/secondPage/(contentSecond:1)', urlAfterRedirects: '/secondPage/(contentSecond:1)', state: Route(url:'', path:'') { Route(url:'', path:'') { Route(url:'secondPage', path:'secondPage') { Route(url:'1', path:':id') } } } )
platform-browser.es5.js:1017 ResolveEnd {id: 4, url: "/secondPage/(contentSecond:1)", urlAfterRedirects: UrlTree, state: RouterStateSnapshot}
platform-browser.es5.js:1026
Router Event: NavigationError
platform-browser.es5.js:1017 NavigationError(id: 4, url: '/secondPage/(contentSecond:1)', error: Error: Cannot activate an already activated outlet)
platform-browser.es5.js:1017 NavigationError {id: 4, url: "/secondPage/(contentSecond:1)", error: Error: Cannot activate an already activated outlet
at RouterOutlet.activateWith (http://localhos…}
core.es5.js:1020
ERROR Error: Uncaught (in promise): Error: Cannot activate an already activated outlet
Error: Cannot activate an already activated outlet
Again, this feels odd since routing back and forth is what I did in 1) and it worked without any errors
Expected behavior
2.1) should behave like 1) since 2.2) behaves like 1) and 3) should work, but does not
Minimal reproduction of the problem with instructions
Use code snippets from above and play around with this example http://plnkr.co/edit/4XHwrIirGojj0fAgt5yn?p=preview
What is the motivation / use case for changing the behavior?
Make named outlets work as expected
Environment
Angular version: 4.3.1
Browser:
- [x] Chrome (desktop) version XX
- [ ] Chrome (Android) version XX
- [ ] Chrome (iOS) version XX
- [ ] Firefox version XX
- [ ] Safari (desktop) version XX
- [ ] Safari (iOS) version XX
- [ ] IE version XX
- [ ] Edge version XX
For Tooling issues:
- Node version: v8.0.0
- Platform: Windows
Others:
Edit: accidentally posted empty issue… closed it, wrote the issue and re-opened it.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 51
- Comments: 30 (1 by maintainers)
This is a major issue and should not be in the Backlog…
for 2 years -are you kidding me?
I believe I am running into the same issue. I have a named outlet that is a child of a path-less component. I have a Plunkr for it. The primary outlet seems to work (Layout A / B); but, the sibling named-outlet is breaking with an unexpected error message,
Error: Cannot match any routes. URL Segment: 'layout-a'
.Plunkr: https://plnkr.co/edit/3HLVIYDdxycups61L8TA
+1
Same issue with Angular 8.2.8
same problem, child empty-path named route cant override parent’s. For example:
{ path: ‘’, component: HeaderComponent, outlet: ‘header’, }, { path: ‘about’, children: [ { path: ‘’, component: AboutComponent }, { path: ‘’, component: EmptyHeaderComponent, outlet: ‘header’, }, ] },
which causes error: Cannot activate an already activated outlet.
Seams still not being fixed with angular 9. Just posting to ensure that this is not closed like https://github.com/angular/angular/issues/10726
The problem is tied to the fact that the RouterModule’s ‘routes’ is configured with an empty path:
Give the root path a name:
Then adjust your links in AppComponent’s template by adding ‘main’ to the links:
After making those changes, your StackBlitz example works properly:
Same problem. All my routes are child routes. I can navigate them to the default page, but not to the named outlet.
Encountering same issue. Migrating to UI Router as this bug has been for almost a year now, and no workaround available.
Anyone figure out this issue? I am running into the same thing.
I managed to bypass this by placing the auxiliary outlet right inside the child component then creating an empty child route and it works. Here’s my code
for instance my
path: 'home', component:HomeComponent
is as follows:hope my approach helps 😉
I struggled with this for a good while. I’m still not sure this is the best way, but here’s what I have:
When redirecting to child route that uses an outlet one always has to use
/path/to/($outlet:$route)
to correctly redirect to that route. I’m not entirely sure what the name for this concept is but here’s something about this in the docs: https://angular.io/guide/router#secondary-route-navigation-merging-routes-during-navigationProps to the Tab-starter project for Ionic which got me on this trail: https://github.com/ionic-team/starters/blob/master/angular/official/tabs/src/app/tabs/tabs.router.module.ts
Also props to this Angular University tutorial which also effortlessly makes use of nested- and what it calls auxilliary-routes: https://blog.angular-university.io/angular-2-router-nested-routes-and-nested-auxiliary-routes-build-a-menu-navigation-system/
I’m still having some trouble setting up the router in the way I believe it would be correct, e.g. the child routes should not have to have to link to absolute routes all the time. This breaks encapsulation. E.g.:
parent-router.ts:
child-router.ts:
If I change
redirectTo: '/main/(expert-overview:expert)',
of the child-route toredirectTo: '(expert-overview:expert)',
I get the error:I believe a child route should not have to know where it is ultimately located since, again, this breaks encapsulation and makes moving around routes unnecessarily hard.
For now I’m just happy that this works. Hope to see some of these things addressed at some point, though.
Some working code:
Hi there, still have that problem.
Child named outlet throws error Error: Uncaught (in promise): Error: Cannot match any routes. URL Segment: ‘suboutlet’ Error: Cannot match any routes. URL Segment: ‘suboutlet’
Stackblitz example here https://stackblitz.com/edit/angular-6eip3n
For anyone reading this using Angular 7, my answer here might be helpful: https://github.com/angular/angular/issues/10981#issuecomment-479482811
Work around the problem:
Another discover that I made is that the named router outlet should be inside the parent component of the child, cannot be in the parent of the parent (cannot be in the grandparent)