Stav Alfi
Stav Alfi

Reputation: 13933

How to share services and state between ngModules

  1. How do we share state using ngrx between ngModules?
  2. How do we share the same service instance between ngModules?

Angular2-RC5.

Upvotes: 4

Views: 965

Answers (1)

BeetleJuice
BeetleJuice

Reputation: 40896

The modules need to have the same instance of the service. To accomplish this, the service needs to be in the providers of your bootsrap AppModule only. Otherwise, if the same service is found in different providers, you could be running parallel instances.

So the question becomes: how to get the service in the top-level providers, but exclude it from all other modules?

With a service you write yourself, it's really straightforward.

  • If the service is part of AppModule, pt it in that module's providers and nowhere else
  • If the service is in another module (let's call it DummyModule) of yours that you're importing into other modules, make sure to not put it in DummyModule's providers or an Angular injector will create a parallel instance of it for every lazy-loaded module that imports DummyModule. Instead, you want to expose that service from a forRoot() static method.

So change:

@NgModule({
  providers: [ MyService]
})
export class DummyModule{ }

To:

@NgModule({
  providers: [] //empty since we want a singleton service
})
export class DummyModule{
  static forRoot() {
    return {ngModule: DummyModule, providers: [ MyService ]};
  }
}

Now when regular modules imports: [DummyModule], they will not get MyService. On the other hand, in AppModule, you have imports: [DummyModule.forRoot()] which exposes the service. As a result, only the top-most component gets the service and you'll have a single instance of it shared among all modules.

With a 3rd party service, it's not straightforward.

Basically, you need the 3rd party developer to make the change above if it's also using @NgModule. Alternatively, instead of importing the 3rd party module, you can create a custom module that declares that module's components, pipes and directives, but implements the change above to put that module's services in a forRoot() method.

This is what I did to get a 3rd party service -- MdIconService (part of an Angular Material module) -- to work as a single instance even though its module isn't yet configured properly. See this github issue.

Upvotes: 6

Related Questions