GCSDC
GCSDC

Reputation: 3540

Angular nested routing with lazy loading issue

I have an app on which I need only the sign in functionality to be available at startup, and all remaining code should be lazy loaded after user authenticates.

I've created a core.module with a core-routing.module and a core.component to handle this, but the child components (for example DashboardComponent) are being rendered inside router-outlet element on app.component.html and not at core.component.html and so the header is not being displayed.

I've already searched and a lot, but couldn't find how to have this working.

app-routing.module.ts

const routes: Routes = [
  { path: '', redirectTo: 'signin', pathMatch: 'full' },
  { path: 'signin', component: SigninComponent },
  { path: 'app', loadChildren: './core/core.module#CoreModule', canLoad: [AuthGuard] },
  { path: '**', redirectTo: 'signin' }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule {}

app.component.html

<router-outlet></router-outlet>

core-routing.module.ts

const routes: Routes = [
  { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
  { path: 'dashboard', loadChildren: './dashboard/dashboard.module#DashboardModule', canLoad: [AuthGuard] },
  { path: '**', redirectTo: 'dashboard' }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class CoreRoutingModule { }

core.component.html

<div id="header">
  <app-header></app-header>
</div>
<main id="content">
  <router-outlet></router-outlet>
</main>

dashboard-routing.module.ts

const dashboardRoutes: Routes = [
  { path: '',  component: DashboardComponent, pathMatch: 'full' }
];

@NgModule({
imports: [
  CommonModule,
  MaterialModule,
  SharedModule,
  RouterModule.forChild(dashboardRoutes)
],

Upvotes: 9

Views: 12614

Answers (3)

GCSDC
GCSDC

Reputation: 3540

After trying it on many different ways, what worked for me was changing core-routing.module.ts to have a single route and including the lazy loaded modules as children inside it:

const routes: Routes = [
  {
    path: '',
    component: CoreComponent,
    children: [
      { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
      { path: 'dashboard', loadChildren: '../dashboard/dashboard.module#DashboardModule', canLoad: [AuthGuard] },
      { path: 'customers', loadChildren: '../customers/customers.module#CustomersModule', canLoad: [AuthGuard] },
      { path: 'history', loadChildren: '../history/history.module#HistoryModule', canLoad: [AuthGuard] },
      { path: 'processing', loadChildren: '../processing/processing.module#ProcessingModule', canLoad: [AuthGuard] },
      { path: '**', redirectTo: 'dashboard' }
    ]
  }
];

Hope this may help someone trying to implement the same functionality.

Upvotes: 11

Aiden Dipple
Aiden Dipple

Reputation: 284

Well, I'm late to the party but just spent the past 5 days solid with the same problem. Posting here in case it helps.

Preamble, don't confuse named outlets per @Asanka response with nested outlets. My first readings through stack overflow I didn't realise the difference so wrongly tried to name outlets and understand how to route to them.

I found the answer by trawling through this excellent article (I'm not the author or affiliated with them):

https://medium.com/@shairez/angular-routing-a-better-pattern-for-large-scale-apps-f2890c952a18

Of particular interest is the linked Stackblitz project (see choose-address-routing.module.ts line #9 that shows the second layer lazy loaded module route requires a fully qualified route).

I also took the day to read every line of this article (whole thread) to clarify my understanding:

https://blog.angularindepth.com/the-three-pillars-of-angular-routing-angular-router-series-introduction-fb34e4e8758e

The complexity resolving my bug was from 2 issues:

  1. I had a reference to my lazy loaded module in another part of my application. The lowest level lazy-load module had a route '' redirect. Because it was already loaded, the redirect was being caught at the root level of the route tree, setting the contents of the top most router outlet (in your example the outlet in app.component.html) instead of the nested outlet (your core.component.html). It looked like it was working but having an issue targeting the correct outlet, but nope, that wasn't it!
  2. The second was that my lowest level lazy-loaded router module didn't use the fully qualified route then when I resolved point #1, I was getting an empty nested outlet but no error letting me know that no route existed.

As per my solution your dashboard-routing.module.ts would look like:

const dashboardRoutes: Routes = [
  { path: '',  , pathMatch: 'full', redirectTo: 'dashboard/child-view' },
  { path: 'dashboard/child-view',  component: DashboardComponent, pathMatch: 'full' }
];

See that 'dashboard/child-view' above! That's what I'm meaning by the fully qualified route to the second level router outlet (populated by the second level lazy loaded module).

I want my 5 days back! I'll accept Shiraz. Keen to hear if this helps you!

Upvotes: 0

Asanka
Asanka

Reputation: 1648

This is because of you have used 2 router outlets. so you have to name the routers to render component to correct one

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

{path: '/examplePath', component: secondComponentComponent, outlet: 'secondRouterOutlet'}

this stackoverflow answer might be helped

Upvotes: 1

Related Questions