1

I've been implementing a new app in Angular 8 which uses lazy loading. However, I've hit an issue I didn't realise existed until now. That is, services loaded in a lazy loaded module creates it's own instance of that service. If I have two lazy loaded modules using the same service, then that service is loaded twice. I have read through a number of issues on stack overflow, including this one: How do I provide a service in a lazy-loaded module and have that service scoped to just the lazy-loaded module and its components?.

I'm hoping someone might be able to help me with my particular requirement / implementation.

I have an app that's split screen.

  • Screen One = Component A & Component B
  • Screen Two = Component B & Component C
  • Screen Three = Component C & many others

In my app-routing.module.ts, I lazy load a screen-one.module & screen-two.module

{ path: 'folders',   loadChildren: '../app/screens/screen-one/screen-one.module#ScreenOneModule' },
{ path: 'folders/:folderID/projects/:projectID',  loadChildren: '../app/screens/screen-two/screen-two.module#ScreenTwoModule'  }

screen-one.module.ts

In this module i import two other modules (folders, projects-lists) which contain the components I need to use in the screen-one.component.html and are displayed as <app-folders></app-folders> & <app-projects></app-projects>

const routes: Routes = [
  {
    path: '',
    component: ScreenOneComponent,
    children: [
      {
        path: ':folderID/projects',
        component: ScreenOneComponent,
      }
    ]
  },
]    
@NgModule({
  declarations: [
    ScreenOneComponent
  ],
  imports: [
    CommonModule,
    RouterModule.forChild(routes),
    FoldersModule,
    ProjectsListModule
  ],
})

The issue I'm having is that I have a similar set up for the screen-two.module where I import ProjectsListModule and ProjectDetailModule.

The issue I'm having is, when using the FoldersService and ProjectsListService, the screen-one.module loads them, and when navigating to screen-two.module, another instance is injected again.

There might be scenarios where a total of 3 or 4 screen modules out of 10 will need access to these services.

  1. Is it worth putting ALL services at the app.module level?
  2. Or is there a way to include services in each module and not have them injected each time a new lazy loaded module is loaded?

UPDATE I've removed any providers associated to the ProjectsListModule and ProjectDetailModule and relied purely on the services forRoot functionality. However, what this currently means is that if I'm on screen 10, then I'll have services querying a database when it's not required. Not sure how to get around this when one of the services querying a database will be needed by about 3 different modules. I'd like it to be used by only those 3 modules, but for it not to have 3 instances.

  • Use `providedIn: 'root'`, as advised in the documentation and as the CLI generates them by default, to provide your service, instead of adding them to the providers of ProjectsListModule: https://angular.io/guide/dependency-injection#create-an-injectable-service-class. Also, Angular 8 changed the way loadChildren works: https://angular.io/guide/router#lazy-loading-route-configuration. – JB Nizet Jul 12 '19 at 08:28
  • Thanks for the response. All the services have `providedIn: 'root'`. Does that mean they will all be loaded globally instead of per module? A tad confused by this. –  Jul 12 '19 at 08:33
  • Yes. Unless of course you also provide them explicitly in a module. Post a complete minimal example reproducing the issue. The most important code is missing in your question. – JB Nizet Jul 12 '19 at 08:38
  • Also, what do you mean by "split screen"? So you mean that the same app is opened in two different browser tabs/frames? If so, you have two instances of the app, with, of course, two instances of the service, and that has nothing to do with lazy loading. – JB Nizet Jul 12 '19 at 08:40
  • No. One screen. One browser. One tab. "Split screen" being a terminology to articulate the design presentation. Component A on the left. Component B on the right. Screen One will import ModuleA and ModuleB for ComponentA and ComponentB. In the screen html, the components are added like so: `` & `` –  Jul 12 '19 at 08:46
  • I've currently removed all providers and relied on 'forRoot'. However, what this currently means is that if I'm on screen 10, then I'll have services querying a database when it's not required. Not sure how to get around this when one of the services querying a database will be needed by about 3 different modules. I'd like it to be used by only those 3 modules, but for it not to have 3 instances. –  Jul 12 '19 at 09:18
  • The CLI and webpack will take care of that for you. – JB Nizet Jul 12 '19 at 09:20
  • Are you able to elaborate? If a user pastes the URL that navigates them to say 'screen-10.module', what's stopping the service that's only needed in 3 of the modules firing and performing an unnecessary database query? (a function in one of the services) - I'm not fully experienced in this area, so any additional info on how it'll be able to know that it doesn't need to use that service on a particular screen would be much appreciated. –  Jul 12 '19 at 09:22
  • Is it just a case that the cli / web pack will detect which components have imported it for it's use? And if so, call that service, if not, leave it alone? –  Jul 12 '19 at 09:27
  • That doesn't even have anything to do with webpack. If the service is not injected anywhere, then it won't be constructed by Angular. if it's not constructed, then it can't do anything. – JB Nizet Jul 12 '19 at 09:27
  • Ah, when you said "CLI and webpack will take care of that for you", I thought you meant that webpack assists in taking care of it for me. But yup, understood. Thanks for your time. Much appreciated. –  Jul 12 '19 at 09:34
  • I thought you were concerned about the JavaScript code being bundled in the main bundle, even though the service is only used in other modules. – JB Nizet Jul 12 '19 at 09:35
  • ah, gotcha! - Feel free to summarise that in a quick answer and I'll mark it as answered. –  Jul 12 '19 at 09:36

0 Answers0