Ionic 4 Modals in Lazy-Loaded Modules

October 4th 2019 Ionic 4

When creating pages using the Ionic CLI, by default each one of them is placed in its own module to enable lazy loading. However, if you want to display such a page as a modal instead of navigating to it, it won't work without some modifications. Although lazy-loaded modal pages are supported in Ionic 4, the documentation isn't all that detailed about it.

The only part it is clear about is that the modal page module must be imported in the module which will be opening the modal page, i.e. to open the ModalPage from the HomePage, the ModalPageModule must be listed among the imports of the HomePageModule:

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    RouterModule.forChild([
      {
        path: "",
        component: HomePage
      }
    ]),
    ModalPageModule
  ],
  declarations: [HomePage]
})
export class HomePageModule {}

However, if you do that with unmodified ModalPageModule as it was generated by the Ionic CLI, you will be surprised when you try navigating to the HomePage: the ModalPage will open instead of the HomePage. The reason for that is the routing defined in the ModalPageModule:

const routes: Routes = [
  {
    path: "",
    component: ModalPage
  }
];

@NgModule({
  imports: [
    CommonModule,
    FormsModule,
    IonicModule,
    RouterModule.forChild(routes)
  ],
  declarations: [ModalPage]
})
export class ModalPageModule {}

This routing configuration overwrites the one from the HomePageModule. Since you won't be navigating to the ModalPage, you don't need any routing for it. To fix the problem, you can therefore remove all the routing configuration from the ModalPageModule:

@NgModule({
  imports: [CommonModule, FormsModule, IonicModule],
  declarations: [ModalPage]
})
export class ModalPageModule {}

Now, the HomePage will open as expected when you try navigating to it. However, you might notice a slight delay. If you look in the browser console, you will find the following error:

ERROR RangeError: Maximum call stack size exceeded

This is caused by another routing issue. When Ionic CLI generates a page, it also adds an entry in the AppRoutingModule (although Ionic 4 is already based on Angular 8, Ionic CLI for some reason still uses the old syntax instead of the new one):

const routes: Routes = [
  { path: "", redirectTo: "home", pathMatch: "full" },
  {
    path: "home",
    loadChildren: () => import("./home/home.module").then(m => m.HomePageModule)
  },
  { path: "modal", loadChildren: "./modal/modal.module#ModalPageModule" }
];

The error is probably the result of having no routes defined in ModalPageModule. Since you don't need any routing for the ModalPage, this can (and should) be safely removed:

const routes: Routes = [
  { path: "", redirectTo: "home", pathMatch: "full" },
  {
    path: "home",
    loadChildren: () => import("./home/home.module").then(m => m.HomePageModule)
  }
];

With this change, the error is gone. To open the modal page, the following code can be used:

async openModal(): Promise<void> {
  const modal = await this.modalCtrl.create({
    component: ModalPage
  });
  return await modal.present();
}

However, the code will fail with the following error:

Error: No component factory found for ModalPage. Did you add it to @NgModule.entryComponents?

Fortunately, you can fix it by following the suggestion included in the error message, i.e. by adding the ModalPage to the entryComponents of ModalPageModule:

@NgModule({
  imports: [CommonModule, FormsModule, IonicModule],
  declarations: [ModalPage],
  entryComponents: [ModalPage]
})
export class ModalPageModule {}

Finally, the modal page opens as expected.

In short, here are the steps required after generating a new modal page with the Ionic CLI:

  1. Add the modal page module as an import to the module from which the modal page will be opened.
  2. Remove the routing configuration from the modal page module.
  3. Remove the route entry for the modal page from the application level routing configuration.
  4. Add the modal page to its module's list of entry components.
Copyright
Creative Commons License