I have some problems with the angular router and named outlets. I have a list of members, and want to edit a clicked member on the same page in a named router outlet. And I would like to have the member handling in a lazy loaded module.
It works when the module is not lazy loaded. The template looks like this:
<tr *ngFor="let member of members">
...
<a [routerLink]="['/home/member', {outlets: {right: ['memberedit', member._id]}}]"> Edit</a>
And the routes array:
const routes: Routes = [
{
path: 'home', component: HomeComponent,
children: [
{
path: 'member', component: MemberComponent,
children: [
{
path: 'memberlist', component: MemberListComponent,
resolve: { resolvedListData: MemberListResolver },
},
{
path: 'memberedit/:id', component: MemberEditComponent,
resolve: { resolvedMember: MemberResolver }
outlet: 'right',
},
]
},
]
},
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: '**', component: NotFoundComponent }
];
When I try to remove he reference to /home/member in order to prepare for lazy loading, it no longer works:
I have tried with:
<a [routerLink]="[{outlets: {right: ['memberedit', member._id]}}]">Edit</a>
This doesn't work, I think this is a known error, the router constructs this URL with a single slash after memberlist:
/home/member/memberlist/(right:memberedit/5f39748b88457a30e32e909d)
And I have tried with:
<a [routerLink]="['../', {outlets: {right: ['memberedit', member._id]}}]"> Edit</a>
It works the first time I click on a member. And gives this URL:
/home/member/(memberlist//right:memberedit/5f39748b88457a30e32e909d)
The second time I click on another member I get this error:
Error: Two segments cannot have the same outlet name: 'memberedit/5f4227887687e3162d94f5a3' and 'memberedit/5f39748b88457a30e32e909d'.
And the URL is:
/home/member/(/(right:memberedit/5f4227887687e3162…f5a3)//right:memberedit/5f39748b88457a30e32e909d)"
I have also tried with:
<a [routerLink]="[{outlets: {primary: ['memberlist'], right: ['memberedit', member._id]}}]">Edit</a>
<a [routerLink]="['../', {outlets: {primary: ['memberlist'], right: ['memberedit', member._id]}}]">Edit</a>
Without any luck.
I have tried with "full pathname" in the lazy loaded module that doesn't work.
<a [routerLink]="['/home/member', {outlets: {right: ['memberedit', member._id]}}]"> Edit</a>
Gives:
url: "/home/member/(memberlist//right:memberedit/5f39748b88457a30e32e909d)", urlAfterRedirects: "/home/member"
And I have tried all the above in the lazy loaded module. Any ideas?
It should work with the lazy-loaded module this way:
const routes: Routes = [
// {
// path: '', component: LazyMemberComponent,
// children: [
{
path: 'list', component: ListComponent,
},
{
path: 'edit/:id', component: EditComponent,
outlet: 'lazyright',
},
// ]
// },
];
const routes: Routes = [
{
path: 'home', component: HomeComponent,
children: [
{
path: 'member', component: MemberComponent,
children: [
{
path: 'list', component: ListComponent,
},
{
path: 'edit/:id', component: EditComponent,
outlet: 'right'
}
]
},
{
path: 'lazymember',
loadChildren: () => import('./lazy-member/lazy-member.module').then(m => m.LazyMemberModule),
component: LazyMemberComponent,
}
]
},
{ path: '', redirectTo: 'home', pathMatch: 'full'}
];
<a [routerLink]="['/home/lazymember', {outlets: {lazyright: ['edit', member.id]}}]">Edit works - No, no longer</a>
It did not work initially with path: '', component: LazyMemberComponent,
because of how Angular Router resolves navigations. Basically, for each child of an UrlSegmentGroup
, it will loop through the current routes array and will try to find a match.
For example, the main UrlSegmentGroup
would look like this:
{
children: {
primary: {
children: {
lazyright: {
children: {},
segments: ['edit', '2']
},
primary: {
children: {},
segments: ['list'],
}
}
segments: ['home', 'lazymember']
}
},
segments: []
}
Then,
'home'
segment will match path: 'home', component: HomeComponent,
'lazymember'
segment will match path: 'lazymember' ...
lazyright
and primary
, both of which must find their match in the current routes array, which is now [{ path: '', component: LazyMemberComponent, children: [...] }]
; this is the reason it did not work beforeIf you'd like to read a bit more about UrlTree
s and UrlSegmentGroup
s, I've written an article on this.