Angular 9中能否在路由外懒加载弹窗相关模块?
Absolutely, you can lazy-load Angular modules outside of routing—but your current approach is missing a critical step: initializing the module's injector, which is why your WidgetAddService and other providers aren't being registered. Let's break down what's wrong and how to fix it.
The Problem with Your Current Code
When you use import('@app/widgets/widgets-add.module'), you're only loading the module's code into the browser. Angular doesn't automatically create an instance of the module or set up its injector, so the providers declared in WidgetsAddModule never get added to your app's dependency injection tree. That's why services like WidgetAddService aren't available when you try to open the modal.
The Fix: Initialize the Lazy-Loaded Module
To make this work, you need to manually create and initialize the module using Angular's createNgModule function (available in Angular 9+). This will set up the module's injector, register its providers, and make its components available.
Here's how to update your openModal method:
import { createNgModule, Injector } from '@angular/core'; import { finalize, switchMap, take } from 'rxjs/operators'; import { from, Observable } from 'rxjs'; // ... constructor(private modalService: MatDialog, private injector: Injector) {} // Inject your current component's injector openModal(): Observable<WidgetModel> { return from(import('@app/widgets/widgets-add.module')) .pipe( switchMap(module => { // Create and initialize the lazy module, linking it to your current component's injector return createNgModule(module.WidgetsAddModule, this.injector); }), switchMap(moduleRef => { // Now the module's providers are available! Retrieve them if needed: const widgetAddService = moduleRef.injector.get(WidgetAddService); // Open the modal—ensure the component is declared in the lazy module return this.modalService.open(ModalAddWidgetComponent).afterClosed() .pipe( take(1), // Clean up the module reference to avoid memory leaks finalize(() => moduleRef.destroy()) ); }) ); }
You also need to fix your WidgetsAddModule to properly declare the modal component and import required dependencies:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ModalAddWidgetComponent } from './modal-add-widget.component'; // Add modules your modal needs (e.g., Angular Material, forms) import { MatDialogModule } from '@angular/material/dialog'; import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ declarations: [ModalAddWidgetComponent], // Declare your modal component here imports: [ CommonModule, MatDialogModule, ReactiveFormsModule ], providers: [WidgetAddService], // For compatibility (Ivy usually handles this, but it's safe to keep) entryComponents: [ModalAddWidgetComponent] }) export class WidgetsAddModule { }
Key Notes
- Injector Linking: By passing
this.injector(your current component's injector) tocreateNgModule, the lazy module's injector inherits providers from the parent tree while adding its own. - Memory Management: Always call
moduleRef.destroy()after the modal closes. This cleans up the module's injector and any services it created, preventing memory leaks. - Component Availability: The modal component must be declared in the lazy module (or imported via another module that declares it) so Angular can resolve it when opening the modal.
Final Verdict
Yes, lazy-loading modules outside of routing is totally feasible in Angular 9+. The missing piece was properly initializing the module's injector to activate its providers and components. The approach above will get your modal and its associated services working as expected.
内容的提问来源于stack exchange,提问作者piernik

