angularangular14angular15angular16angular-lazyloading

Angular15 lazy loading not working if its not explicitly imported


Working with Angular15.

Create a lazy loading modules

app-routing.module.ts

    const routes: Routes = [
      { path: '', redirectTo: '/dashboard', patchMatch: 'full' },
      { path: 'dashboard', loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule) },
      { path: 'module1', loadChildren: () => import('./module1/module1.module').then(m => m.FirstModule) },
      { path: 'module2', loadChildren: () => import('./module2/module2.module').then(m => m.SecondModule) },
      { path: 'module3', loadChildren: () => import('./module3/module3.module').then(m => m.ThirdModule) },
      { path: 'module4', loadChildren: () => import('./module4/module4.module').then(m => m.FourthModule) },
    ];

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

dashboard.module.ts -- Having components dependency with FirstModule, SecondModule, ThirdModule and FourthModule

const routes: Routes = [
  { path: 'dashboard', component: DashboardComponent},
];

@NgModule({
declarations: [DashboardComponent, DashboardDetailsComponent]
imports: [RouterModule.forChild(routes), FirstModule, SecondModule, ThirdModule, FourthModule]
exports: [RouterModule],
bootstrap: [DashboardComponent]
})
export class DashboardModule {}

module1.module.ts -- Having components dependency with SecondModule and ThirdModule

const routes: Routes = [
  { path: 'module1', component: Module1Component},
  { path: 'module1/details', component: Module1DetailsComponent},
];

@NgModule({
declarations: [Module1Component, Module1DetailsComponent]
imports: [RouterModule.forChild(routes), SecondModule, ThirdModule]
exports: [RouterModule],
bootstrap: [Module1Component]
})
export class FirstModule {}

module2.module.ts -- Having components dependency with ThirdModule

const routes: Routes = [
  { path: 'module2', component: Module2Component},
  { path: 'module2/details', component: Module2DetailsComponent},
];

@NgModule({
declarations: [Module2Component, Module2DetailsComponent]
imports: [RouterModule.forChild(routes), ThirdModule]
exports: [RouterModule],
bootstrap: [Module2Component]
})
export class SecondModule {}

With the above code getting error Error: NG04007: The Router was provided more than once. This can happen if 'forRoot' is used outside of the root injector. Lazy load modules hould use RouterModule.forChild instead

Its working fine only if DashboardModule is explicitly imported in AppRoutingModule

Solution

  • Below is a comprehensive example of using lazy-loading, sharing-components between modules, But first lets look at what went wrong!


    Now lets focus on sharing components/directives.

    app routing ts

    import { NgModule } from '@angular/core';
    import { RouterModule, Routes } from '@angular/router';
    
    const routes: Routes = [
      { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
      {
        path: 'dashboard',
        loadChildren: () =>
          import('./dashboard/dashboard.module').then((m) => m.DashboardModule),
      },
      {
        path: 'module1',
        loadChildren: () =>
          import('./module1/module1.module').then((m) => m.FirstModule),
      },
      {
        path: 'module2',
        loadChildren: () =>
          import('./module2/module2.module').then((m) => m.SecondModule),
      },
      {
        path: 'module3',
        loadChildren: () =>
          import('./module3/module3.module').then((m) => m.ThirdModule),
      },
      {
        path: 'module4',
        loadChildren: () =>
          import('./module4/module4.module').then((m) => m.FourthModule),
      },
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes, { useHash: true })],
      exports: [RouterModule],
    })
    export class AppRoutingModule {}
    

    module 1 routing ts

    import { NgModule } from '@angular/core';
    import { RouterModule, Routes } from '@angular/router';
    import { Module1Component } from './module1/module1.component';
    import { Module1DetailsComponent } from './module1-details/module1-details.component';
    
    const routes: Routes = [
      { path: '', redirectTo: 'module1', pathMatch: 'full' },
      { path: 'module1', component: Module1Component },
      { path: 'module1/details', component: Module1DetailsComponent },
    ];
    
    @NgModule({
      imports: [RouterModule.forChild(routes)],
      exports: [RouterModule],
    })
    export class Module1RoutingModule {}
    

    module 1 ts

    import { NgModule } from '@angular/core';
    import { CommonModule } from '@angular/common';
    
    import { Module1RoutingModule } from './module1-routing.module';
    import { Module1Component } from './module1/module1.component';
    import { Module1DetailsComponent } from './module1-details/module1-details.component';
    import { SecondModule } from '../module2/module2.module';
    import { ThirdModule } from '../module3/module3.module';
    import { SharedModule } from '../shared/shared.module';
    
    @NgModule({
      declarations: [Module1Component, Module1DetailsComponent],
      imports: [
        CommonModule,
        Module1RoutingModule,
        SecondModule,
        ThirdModule,
        SharedModule,
      ],
      exports: [Module1Component], // <- exporting for dashboard to use
    })
    export class FirstModule {}
    

    dashboard module using component of module 1

    import { NgModule } from '@angular/core';
    import { CommonModule } from '@angular/common';
    import { DashboardDetailsComponent } from './dashboard-details/dashboard-details.component';
    import { DashboardComponent } from './dashboard/dashboard.component';
    import { RouterModule, Routes } from '@angular/router';
    import { FirstModule } from '../module1/module1.module';
    import { SecondModule } from '../module2/module2.module';
    import { ThirdModule } from '../module3/module3.module';
    import { FourthModule } from '../module4/module4.module';
    import { SharedModule } from '../shared/shared.module';
    import { Module1Component } from '../module1/module1/module1.component';
    
    const routes: Routes = [
      { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
      { path: 'dashboard', component: DashboardComponent },
      { path: 'from-module1', component: Module1Component }, // using module 1 file
    ];
    
    @NgModule({
      declarations: [DashboardComponent, DashboardDetailsComponent],
      imports: [
        RouterModule.forChild(routes),
        FirstModule,
        SecondModule,
        ThirdModule,
        FourthModule,
        SharedModule,
      ],
    })
    export class DashboardModule {}
    

    shared module, stores components/etc which is shared by all!

    import { NgModule } from '@angular/core';
    import { CommonModule } from '@angular/common';
    
    @NgModule({
      declarations: [],
      imports: [CommonModule],
      exports: [CommonModule],
    })
    export class SharedModule {}
    

    Stackblitz Demo -> cd test -> npm i -> npm run start