Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 ?

like image 432
RickC137 Avatar asked Apr 01 '20 13:04

RickC137


People also ask

How do you use a lazy load module without routing?

define where we want to load our component in the template with the ng-template tag, define its view query through ViewChild decorator, which gives us access to the DOM and defines the container to which the component will be added, finally, dynamic import the component and add it to the container.

How are modules loaded lazily in Angular?

To lazy load Angular modules, use loadChildren (instead of component ) in your AppRoutingModule routes configuration as follows. content_copy const routes: Routes = [ { path: 'items', loadChildren: () => import('./items/items. module'). then(m => m.

Why we use lazy loading in Angular?

Why do we need Lazy Loading in Angular 4? Lazy loading is a technique in Angular that allows you to load JavaScript components asynchronously when a specific route is activated. It improves the speed of the application load time by splitting the application into several bundles.


1 Answers

  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);
like image 113
Ostn Avatar answered Oct 06 '22 05:10

Ostn