4

I have a service in angular 2 that in its current form only listens to events from a custom dispatcher, acts on them and sends other events through the dispatcher.

So the service isn't injected anywhere nor do I want it to (it will later be injected in components of lazily loaded modules).

The service resides in a shared module and I export it like so:

export class SharedModule {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: SharedModule,
      providers: [Dispatcher, AccountService]
    };
  }
}

How do I make sure it gets instantiated when SharedModule loads?

Hampus
  • 2,769
  • 1
  • 22
  • 38
  • Why do you want to instantiate the service on module load? it seems a bit messy since you should rely on the first call rather than on the instanciation. – Supamiu Oct 11 '16 at 09:13
  • So what's wrong with this way? this is the correct way. – micronyks Oct 11 '16 at 09:14
  • @Supamiu The service needs to be instantiated when the app loads because it is listening to events concerning the login state handled by another service. All consumers of the service are lazy so waiting for any of them to inject it will surely make it miss crucial events. Also, those lazy modules will not be loaded until the accountService approves. There are of course all sorts of ways I can hack around this but I am looking for the right way. – Hampus Oct 11 '16 at 09:27

1 Answers1

4

You can use NgModule's constructor. In this example I'm using it to instantiate UserService and replaceReducers() for ngrx/store when I lazy load this module:

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    ...
  ],
  providers: [
    UserService,
    ...
  ],

})
export class LazyModule {
  constructor(
    private userService: UserService,
    private store: Store<any>) {
    console.info(`replaceReducer(${ModuleRootReducer.name})`);
    this.store.replaceReducer(ModuleRootReducer);
  }
}
Sasxa
  • 40,334
  • 16
  • 88
  • 102
  • Hmm.. Should I inject it in the constructor of the shared module or in the app module? Do I keep it in the provider array returned by forRoot in the shared module to make sure it is a system wide singleton? – Hampus Oct 11 '16 at 09:22
  • This isn't my AppModule, it's the module I load with `loadChildren: 'app/feature/feature.module#LazyModule'`. I put `UserService` in the providers array of this module, so it will be available for LazyModule and all other modules I import here. AppModule doesn't have access to `UserService`, as it shouldn't in my case... – Sasxa Oct 11 '16 at 09:28
  • Awesome, it was a single row fix. I just injected it into the constructor of the shared module. How would this work if the initialisation of accountService was asynchronous. That is, if I wanted to call an `init(): Promise` method before anything else continued? – Hampus Oct 11 '16 at 09:34
  • I guess you could return Observable/Promise other services can subscribe to. I use `firebase.auth` in my AppModule to authenticate user, then on success I load this module, which loads user data. My pages then access this user data with `get user(): User { return this.userService.user };`. I've also used `
    ` on root page of this route (where `` is)...
    – Sasxa Oct 11 '16 at 09:41