0
votes

I have a route / component that requires a route parameter and has a named outlet. I want to lazy load a module and activate this route. Here are my routes:

Profile Module (sub module) Routes:

const routes: Routes = [
{
  path: ':id', component: ProfileComponent
  children: [
   { path: 'list/:id', component: ListComponent, outlet: 'sidebar' },
   { path: 'risk/:id', component: RiskComponent, outlet: 'sidebar' }
  ], 
];

Parent Module Routes

const routes: Routes = [
  { path: 'projects/profile',
    loadChildren: './profile/profile.module#ProfileModule' }
 ]

Loading the route results in the error:

Error: Cannot match any routes. URL Segment: 'projects/profile/-3'

When I use an empty string for the path in the sub module, there is no error and the module loads but the component doesn't load. I found this help with lazy loading route params and this help with lazy loading named router outlets, but neither worked.

My question is: How do I lazy load a route with a route parameter and named router outlet?

--Edit--

Here is a demo app that shows my problem. I created 3 main routes: one that lazy loads a submodule without named outlets, one the that lazy loads with a named outlet, and one that doesn't use lazy loading. In the UI, the link to the route that has a named outlet produces the error above.

3

3 Answers

1
votes

You seem to have component: ProfileComponent twice. Is that what you want? That might be causing the routing issue.

Also, for lazy loading your module which contains it's children, in your parent route, you can also do:

const routes: Routes = [
  { path: 'projects/profile',
    loadChildren: () => import('./profile/profile.module').then(m => m.ProfileModule')
  }
 ]

If you had a demo app diagnosing it would be helpful. A StackBlitz example could help more.

UPDATE:

In you app.module.ts:

const routes: Routes = [
  { path: 'profile',
    loadChildren: () => import('./profile/profile.module').then(m => m.ProfileModule')
  }
 ]

In your profile.routing.ts:

const appRoutes: Routes = [
  {
    path: '', 
    pathMatch: 'full',
    component: ProfileComponent,
  },
  {
    path: 'sidebar', component: SidebarComponent,
    children: [
    {
     path: ':id',
    component: AdminUserDetailsComponent,
    }
    ]
  },
];

I don't think you need the name="sidebar" in. Make it` because you're already inside a module. PathMatch: 'full':

pathMatch = 'full' results in a route hit when the remaining, unmatched segments of the URL match is the prefix path

https://angular.io/guide/router#set-up-redirects

Finally, you links should navigate to the full path:

  <a [routerLink]="['/profile/sidebar']">Outlet defined and specified doesn't work (ProfileModule)</a>
  <a [routerLink]="['/profile']">With outlet defined but not specified (ProfileModule: '/profile/3')</a>

I never use inline params route because they are difficult to read, navigate, figure out and debug.

0
votes

It shouldn't be different from classic lazy loading, what may be causing the problem is path: ':id' in profile routing, try changing it to empty path: '', you may also move the :id up to the parent route path: 'projects/profile/:id'

0
votes

So after trial and error I found an answer. I created this demo that implements it. As a note I need multiple router-outlets with route params (the demo only contains a component that has one router outlet, but my actual app has two. Hence I need it to be named)

Parent Module

As Thomas Cayne mentions, the link to lazy loading the module is the following (Note the lack of :id route parameter. This is because this route is used for lazy loading only):

{ path: 'profile', loadChildren: () => import('./profile/profile.module').then(m => m.ProfileModule) },

Sub Module

The routing in the submodule is the following: (The top level route has the :id route param as its component needs to use the :id. The child outlet in my case requires an :id as well. The outlet uses the param to load its data.)

 const appRoutes: Routes = [
  { 
   path: 'test/:id', component: ProfileComponent,
   children: [
    { path: 'bar/:id', component: SidebarComponent, outlet:'sidebar' }
   ] 
  },
 ];

Parent Template

Finally the routerLink that correctly routes to the component with a named router outlet and route params through a lazy loaded module is as follows:

<a [routerLink]="['/', 'profile', 'test', 3, { outlets: { sidebar: ['bar', 3 ] } }]">Working Router outlet and route params</a>