0

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.

afriedman111
  • 1,925
  • 4
  • 25
  • 42

4 Answers4

2

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.

Thomas Cayne
  • 1,132
  • 8
  • 15
  • Here is a [demo app](https://stackblitz.com/edit/angular-8-communicating-between-components-x7phcm) I created StackBlitz. 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 lazyloading. Any help would be greatly appreciated. – afriedman111 Jul 30 '19 at 18:34
  • Thanks for the demo. It was very helpful. Please see my update above – Thomas Cayne Jul 30 '19 at 21:35
  • Thank you very much for the answer. I do, however need the named router outlet as my actual application has two outlets on the ProfileComponent page. I only had one for brevity purposes. Those outlets need route parameters as well. After some testing I found something that works. I posted an answer. – afriedman111 Jul 31 '19 at 13:17
0

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'

Vojtech
  • 2,756
  • 2
  • 19
  • 29
  • I tried moving the :id up to the parent and it doesn't work. However, it does work if I remove the :id entirely, but my page doesn't load. (I got the idea to add the id to the sub module route from the first link I provided above) – afriedman111 Jul 29 '19 at 22:42
  • After trying a number of permutations, I did get this to partially work. After moving the :id to the parent I found that the following route worked: http://localhost:4200/projects/profile/18. However, the named router outlets did not work. The navigating to the route: http://localhost:4200/projects/profile/18/(sidebar:list/18) gives the error mentioned above. – afriedman111 Jul 30 '19 at 00:26
  • I added an example project above. Any feed back would be greatly appreciated. – afriedman111 Jul 30 '19 at 18:57
0

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>
afriedman111
  • 1,925
  • 4
  • 25
  • 42
0

After looking at this info https://newbedev.com/angular-4-lazy-loading-with-named-router-outlet-not-working A workaround is to avoid blank paths in lazy loaded modules when using named outlets. Angular has a bug for this, but it was closed since no one would provide an example. https://github.com/angular/angular/issues/16406

Try this in your stackblitz project:

  path: 'profileoutlet', component: ProfileComponent,
   children: [
    { path: 'bar/:id', component: SidebarComponent, outlet:'sidebar' }
  ] 

in profile.routing.ts and

  <a [routerLink]="['/', 'profile', 3, 'profileoutlet', { outlets: { sidebar: ['bar', 3 ] } }]">Outlet defined and specified doesn't work (ProfileModule)</a>

for the link in app.component.ts

Duane W.
  • 3
  • 2