'Angular lazy load with named outlet not working

I created a products folder which contains products-home.component(parent) and products-list.component(child) with named outlet.

I get Error: Cannot match any routes. URL Segment: 'products' when navigated to products-list using lazy load.

This is working when it is eagerly loaded

app.module.ts

@NgModule({
  imports:      [ ...,ProductsModule ]
})

products.module.ts

@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: "products",
        component: ProductsHomeComponent,
        children: [
          {
            path: "products-list",
            component: ProductsComponent,
            outlet: "content"
          }
        ]
      }
    ])
  ]
})

This is not working when it is lazy loaded

app.module.ts

const LazyRoutes: Routes = [
  {
    path: 'products',
    loadChildren: './products/products.module#ProductsModule'
  }
];
@NgModule({
  imports:      [ RouterModule.forRoot(LazyRoutes) ]
})

products.module.ts

@NgModule({
  imports: [
    RouterModule.forChild([
      {
        path: "",
        component: ProductsHomeComponent,
        children: [
          {
            path: "products-list",
            component: ProductsComponent,
            outlet: "content"
          }
        ]
      }
    ])
  ]
})

Stackblitz



Solution 1:[1]

This is a known issue in angular - 22346 and 10981

When module is lazy load then parent component's path needs to be set as empty. This is the issue here, the child component with named outlet only works when parent has a path(non-empty).

I got this working by adding fake path.

{
    path: "home", <--Here
    component: ProductsHomeComponent,
    children: [
      {
        path: "products-list",
        component: ProductsComponent,
        outlet: "content"
      }
    ]
}

Since the route config is changed, we have to change routerLink as 'products/home'

<a [routerLink]="['/products/home', { outlets: { 'content': ['products-list'] } }]">Navigate to Products(Products List)</a>

Solution 2:[2]

2021 Update... Tested from V7 to V12

In order to use a lazy loaded module's named outlet, you have to navigate to the module's pages within component in which the router is defined. For example:

Consider this:

lazyModule.component.ts

<div>
  <a [routerLink]="[{outlets: {namedRouter: 'innerComponent'}}]">Open Link in Named Route</a><br>
  <router-outlet></router-outlet>
  <router-outlet name = 'namedRouter'></router-outlet>
</div>

Clicking the anchor tag WILL show the route named 'innerComponent' in the 'namedRouter' outlet.

HOWEVER... For one reason or another, changing the route for the 'namedRouter' from any other nested component (regardless if it's in the same module) WILL NOT WORK. In code terms:

nestedComp.component.ts

<div>
  <button [routerLink]="{outlets: {namedRouter: 'aValidRoute'}}">IT SHOULD WORK, BUT IT DOESN'T</button> <!--- This will fail to resolve the route if called within the conteXt of the lazy loaded module. --->
</div>

If you would like to change the route dynamically from other components, I would suggest that one implements an Observable element (for example, in lazyModule.component.ts) that listens to routes thrown at it and invokes a router change. See eXample below:

someService.ts

private routeBS: BehaviorSubject = new BehaviorSubject(null);
routeObs = this.routeBS.asObservable();

changeNamedRouterRoute(route: string): void {
  this.routeBS.next(route);
}

lazyModule.component.ts

<div>
   <router-outlet></router-outlet>
   <router-outlet name = 'namedRouter'></router-outlet>
 </div>

 export class LazyModuleComponent implements OnInit {
   
   constructor(
     private service: SomeServiceService,
     private router: Router,
     private route: ActivatedRoute
   ) {}

   ngOnInit() {
     this.service.routeObs.subscribe(res => {
       this.router.navigate([{outlets: {namedRouter: res}}], {relativeTo: this.route.parent}).then(acc => {
           // do something when the router gives you the nod
       }).catch(err => {
           console.log(err);
           // do something when the router event fails
       });
     });
   }
 }

In other components that should directly set routes to the 'namedRouter', inject the 'someService' service through the constructor AND then call the service's changeNamedRouterRoute() function specifying the desired route as the only argument.

HOPE THIS HELPS SOMEONE, I was stuck on this for almost 6 hours and the internet didn't give me any solid breaks. The GitHub issues were closed due to inactivity without closure, but i am sure some may find this quite useful.

Solution 3:[3]

That work for me,

The following configuration in the "routing" of the lazy module:

const routes: Routes = [
    {
      path: '',
      component: LazyDownloadComponent,
      children: [
        {
          path: 'test',
          outlet: 'left',
          loadChildren: () =>
            import('./modules/another.module').then(
              (m) => m.Another
            ),
        },
      ],
    },

Parent component:

<router-outlet name="left"></router-outlet>

url in the browser:

http://localhost:4200/parentComponent/(left:test)

BE CAREFUL WITH THE "/" BETWEEN THE PATH AND THE "("

I hope this helps someone, as @taffy did for me

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 Sameer
Solution 2
Solution 3 Basilio