Angular15 lazy loading not working if its not explicitly imported

76 views Asked by At

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
1

There are 1 answers

0
Naren Murali On BEST ANSWER

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

  • The forRoot should be used for the root level module ( here AppModule ) for all the lazy loaded routes we need forChild, in your example for the app.routing.ts you are using forChild, so I guess thats where it went wrong!

  • You only need to export the essential components that need to be shared to other components, so there is no need to export RouterModule, this can be done only if you are defining a separate file for routes module1.routing.ts there is no need to export it!


Now lets focus on sharing components/directives.

  • If you are going to use something that is shared by all the modules, its better you create a module called SharedModule this will contain the common items for all modules, eg CommonModule is definetely required by all the modules, you can also share components. The important part is that, the component/directive needs to be in the declarations array of only one module and should be present in the exports array also for other modules to use it!

  • If you are sharing components/directives between only few modules, you can declare the component only on the original module but you need to add it to the exports array for it to be accessible by other modules, in the below example provided I am exporting module1Component from module1 and using it in the dashboardModule

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