简体   繁体   中英

How to dynamically lazy load module without router - Angular 9

I have several modules that I want to lazy load dynamically, I am upgrading from v8 to v9, with the version 9 of angular the logic concerning modules seems to have changed. What is the best way of doing it?

  1. Component with no module

If we want to lazy-load a component dynamically (with no module), then we can use the same pattern as with routes:

// <ng-template #myContainer></ng-template>    
@ViewChild('myContainer', { read: ViewContainerRef }) container: ViewContainerRef;
  
const { MyLazyComponent } = await import('./path/to/lazy/component');
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(MyLazyComponent);
const { instance } = this.container.createComponent(componentFactory);
  1. Modules

If the component depends on other services / components then we need to load the full module. Because it will be lazy loaded (not compiled initially) we need to run the compilation "manually". It is still easier than previous tricks used on previous versions of Angular. Here is a solution.

We can create a service that store module references, and load the component into a container (given a module ID and a container reference).

import { Injectable, Compiler, Injector } from '@angular/core';

@Injectable({
    providedIn: 'root'
})
export class LazyComponentService {

    private componenttRefs = {
        myFirstLazyModuleId: import('../path/to/first/lazy/module/component.module'),
        mySecondLazyModuleId: import('../path/to/second/lazy/module/component.module')
    };

    constructor(
        private compiler: Compiler,
        private injector: Injector,
    ) { }

    async loadComponent(moduleId, container) {

        let ref;
        try {
            const moduleObj = await this.componenttRefs[moduleId];
            const module = moduleObj[Object.keys(moduleObj)[0]];
            const moduleFactory = await this.compiler.compileModuleAsync(module);
            const moduleRef: any = moduleFactory.create(this.injector);
            const componentFactory = moduleRef.instance.resolveComponent();
            ref = container.createComponent(componentFactory, null, moduleRef.injector);
        } catch (e) {
            console.error(e);
        }
        return ref;

    }

}

Modules need to be compiled. We do it by calling resolveComponentFactory inside each module's constructor:

@NgModule({
  imports: [
    MyModules...
  ],
  declarations: [
    MyFirstLazyComponent
  ]
})
export class MyFirstLazyComponentModule {

  constructor(private componentFactoryResolver: ComponentFactoryResolver) { }

  public resolveComponent(): ComponentFactory<MyFirstLazyComponent> {
    return this.componentFactoryResolver.resolveComponentFactory(MyFirstLazyComponent);
  }

}

And then the magic is up, you can dynamically lazy load a component to a container:

  const myFirstLazyComponent = await this.lazyComponentService.loadComponent(myFirstLazyModuleId, containerRef);

I have several modules that I want to lazy load dynamically, I am upgrading from v8 to v9, with the version 9 of angular the logic concerning modules seems to have changed. What is the best way of doing it ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM