4

I have an @Injectable service in my application that is added as a provider in AppModule. I want to make sure no one in my development team injects it in any other module. A single instance is enough and it has some complicated logic that I don't want to be run twice. Any ideas?

I know how DI works in angular 2, so answers like 'Make sure it is added as a provider only in App Module' won't help. :(

PLEASE NOTE, that I want it to produce some sort of error at build or run time if the service is provided to any other but AppModule.

eddyP23
  • 6,420
  • 7
  • 49
  • 87

1 Answers1

7

Angular maintains a single instance per provider.

Ensure you provide a service only once and DI will ensure that there is only one single instance in your application.

If you provide a service on a comonent @Component({ ..., providers: [...]}), then there will be as many instances as component instances.

If you provide a service only in providers of AppModule or providers of modules imported to AppModule, then there will only be a single instance for your whole application:

@NgModule({
  providers: [...],
  imports: [...]
})
export class AppModule {}

A pitfall are lazy loaded modules. If a module is lazy loaded then providers provided there will cause another instance to be created, because lazy loaded modules have their own DI root scope. For lazy loaded modules implement forRoot() and add providers that should be application-wide singletons only in forRoot(), but not in providers and import it in AppModule

@NgModule({
  providers: [...],
  imports: [LazyLoadedModuleWithSingltonProvider.forRoot()]
})
export class AppModule {}

update

To prevent instantiation of multiple instances of a service you can use a workaround like

@Injectable()
export class MyService {
  private static instanceCounter = 0;
  private instanceNumber = instanceCounter++;

  constructor() {
    if(this.instanceNumber > 0) {
      throw 'MyService must be kept a singleton but more than one instance was created';
    }
  }
}

Another way is to move singleton services to a CoreModule and prevent this module being imported anywhere else than in the AppModule

https://angular.io/docs/ts/latest/guide/ngmodule.html#!#prevent-reimport

Only the root AppModule should import the CoreModule. Bad things happen if a lazy loaded module imports it.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • I do mention in my question that this does not answer the question. If one of the devs on my team adds this service to any other module as a provider, there will be multiple instances of the service. I want to force that it produces an error while building or at least at runtime. – eddyP23 Jan 20 '17 at 15:01
  • You are right. I somehow forgot about that while answering :-/. I updated my answer. Angular doesn't provide anything. – Günter Zöchbauer Jan 20 '17 at 15:10