[Fixed] How to lazy load module based on some condition using useFactory in angular?

Issue

I have an angular project with large amount of modules and components in which, I want to show module’s component based on some business logic.
I want using angular’s powerful feature i.e. lazy loading which will allow me to make my application lite.

What I want to Do :

Suppose, I have one bookStore site on which lot’s of readers spent time with reading online articles.
I want to show different module based on reader's role. if reader’s role is admin or staff then they can access all the feature and components. if reader’s role is normal then they can view only some component.

For that, I make this kind of structure :

enter image description here

For achive this feature. we must keep our route same for both the module and for that, I have to use useFactory method of angular that will allow me to run custom function for update InjectionToken(ROUTES) which is already used by angular itself for compile and load module.

My module flow is like this :

enter image description here

All three modules (reader-handler, admin/reader and user/reader) are lazy loaded modules.
reader-handler module’s path is defined in route file but other two module’s path will append in ROUTES dynamically using useFactory function.

Here is my code :

providers: [{
    provide: ROUTES,
    useFactory: decideWhichModuleToLoad,
    deps: [ReaderService],
    multi: true,
  }]

export function decideWhichModuleToLoad(readerService: ReaderService) {
   readerService.getReaderType().subscribe((result) => {
    let routes: Routes = [];
    if (result && result?.Role) {

      if (result.Role == 'admin') {
        routes = [{
          path: '',
          loadChildren: () =>
            import('../admin/read.module').then((m) => m.ReadModule)
        }]
      }
      else {
        routes = [{
          path: '',
          loadChildren: () => import('../user/read.module').then((m) => m.ReadModule)
        }]
      }
    }
    else {
      routes = [{
          path: '',
          loadChildren: () => import('../user/read.module').then((m) => m.ReadModule)
        }]
    }
    return routes;
  });
}

I wrote this code in read-handler module So. when this module load, it’s useFactory will execute and update ROUTES variable which is already used by angular.

It works and load module if I return route directly without wait for condition and subscription response from service.
If I run above code then My child component and module that is load dynamically will be undefined. because angular already compile ROUTES before we update it.
Error is look like this :

enter image description here

I am following this Tutorial for dynamic Routing : How to load different module on same route
And Angular say that it’s angular’s bug that before useFactory resolve, angular compile ROUTES injectionToken. (Cannot read property ‘loadChildren’ of undefined" error)

Anyone guys know how can I resolve this error… and keep angular waiting for resolve usefactory.
Any small suggestion would be helpful for me.

Solution

You’re setting routes inside a subscribe and it’s asynchronous. You can try to call getReaderType before entering in decideWhichModuleToLoad function and store it somewhere so you can use it directly from your useFactory.

Leave a Reply

(*) Required, Your email will not be published