2

I would like to have some explanations about singleton services in Angular2. I made a quick example in a plnkr : http://plnkr.co/edit/09XVxN?p=preview

Try to change the displayed component by clicking on both buttons. You will see in the debugger console ServiceA constructor console.log messages.

Why AService in this case isn't a singleton ? Because each time we switch the displayed component it calls the AService constructor...

Thanks by advance

Romain
  • 756
  • 1
  • 5
  • 13

2 Answers2

1

When you add a service to the providers: list of a component you get a new instance for every component.
Add it only to bootstrap(AppComponent, [AService]) and the whole application gets the same reference.

In Angulars DI every provided instance is a singleton, but only within the scope of the injector that created the instance.
Angulars DI is hierarchical. For each component a child-injector is created. DI starts with the closest injector to resolve the required type. If there is a provider but no instance yet, one will created. If there is no provider DI iterates to the parent injector until it finds one or until it reaches the root injector. If it reached the root injector and still didn't find a provider it throws.

The providers added to bootstrap() are the providers for the root injector and therefore applicable for the whole application when not further down the hierarchy another injector has a provider for the same type registered.

Günter Zöchbauer
  • 558,509
  • 191
  • 1,911
  • 1,506
  • Would you kindly update this to be relevant to Angular 7? Specifically, how to ensure `ctor()` is only called once(i.e. singleton)? – ttugates Mar 07 '19 at 18:22
  • Only provide it in a module that is **not** lazy-loaded and you should be fine or if you have to provide it in a lazy-loaded module, provide it in `forRoot` (you should be able to find more about that) to ensure the service provided in a non-lazy-loaded module anyway. If you provide it also on a component or directive then you again can get different instances, so do not do that if you want a singleton. – Günter Zöchbauer Mar 07 '19 at 18:24
  • So would decorating the service with `@Injectable({ providedIn: 'root' })` ensure its a singleton? Since that provides for root injector. – ttugates Mar 07 '19 at 18:25
  • I haven't used Angular 7 and don't know what `providedIn` does. According to the docs it seems to do something like `forRoot`. – Günter Zöchbauer Mar 07 '19 at 18:27
  • 1
    Its added to service created by Angular CLI as of Angular 6. Thanks for help tho.. See: https://angular.io/guide/providers#providing-a-service – ttugates Mar 07 '19 at 18:29
1

In fact, it depends on where you put the corresponding providers:

  • If you put it at the bootstrap level, you'll have a single instance for the whole application

    bootstrap(AppComponent, [ MyService ]);
    
  • If you put it at the component level, you'll have an instance for each component instance.

    @Component({
      (...)
      providers: [ MyService ]
    })
    export class MyComponent {
      (...)
    }
    

This is because of the hierarchical injectors of Angular2. You can make a bit finer since it's possible to use providers from parent component as well...

This answer could give you more details about this:

Community
  • 1
  • 1
Thierry Templier
  • 191,422
  • 38
  • 386
  • 349
  • update: the new syntax `platformBrowserDynamic().bootstrapModule(AppModule)` where app module would provide `MyService ` – William Lohan Mar 07 '19 at 18:19
  • Would you kindly update this to be relevant to Angular 7? Or I can ask another question at risk of being marked as duplicate. Specifically, how to ensure `ctor()` is only called once(i.e. singleton)? – ttugates Mar 07 '19 at 18:22