Angular 2 - Singleton Services?

17,376

Solution 1

What you have shown is a correct way. It creates single instance which will be shared among components.

https://plnkr.co/edit/FBCa39YC4ZPoy6y8OZQl?p=preview for reference purpose.

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent }  from './app.component';
import {service} from './service';
@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent],
  providers:[service],

  bootstrap:    [ AppComponent ]
})
export class AppModule { }

Solution 2

I also want to create an Object for using as a provider in angular2 so i created an @injector. but if we set provider in each @component and import it, then each component uses different object of injector. for creating singleton provider, I declared this provider in parent component and import it in each, now its working fine. https://angular.io/guide/dependency-injection

Solution 3

A Singleton Service shall only be kept in app.module.ts "providers" (array)

and it shall not be placed in any other component or service provider (array).

if this is done correctly then angular 2 - 2.4.0 - Singleton works perfectly

Solution 4

Ok let me try to explain how services work according to me experience and basically to the documentation.

There are 3 main scenarios:

  • The service is included in providers array on a component level - the service can be injected in the parent and all children.

  • The service is included in providers array on a module level - everything that is in this module knows about the service.

  • The service is included in providers array on a module level - everything that is in this module knows about the service but if you use component from this module inside another component from another module which imports first module then the instance of the service for this component will be different.

Share:
17,376
ouah
Author by

ouah

Updated on June 09, 2022

Comments

  • ouah
    ouah about 2 years

    In Angular 1 I frequently used factories for services to store shared state accessible by many components. It looks like in Angular 2 all services that are injected as @Injectable() are created each time, thus losing the shared state.

    I 'register' the service at the root module's providers meta key, but still I get a transient instance.

    What I have:

    Injectable()
    export class ArtistService {
       constructor(private http:Http) {
         // firing on each injection
         console.log("ArtistService ctor");
       }
    
    }
    

    to call it in a component then:

    @Component({
        selector: 'artist-display',
        templateUrl: './artistDisplay.html',
    })
    export class ArtistDisplay  {
        constructor(private artistService: ArtistService) {
               // instance is fine but transient
        }
    }
    

    And the definition of the module:

    @NgModule({
      declarations: [...],
      imports: [BrowserModule, FormsModule, HttpModule,
        RouterModule.forRoot(rootRouterConfig)],
      providers   : [
          ArtistService,
    
          // make sure you use this for Hash Urls rather than HTML 5 routing
          { provide: LocationStrategy, useClass: HashLocationStrategy },
      ],
      bootstrap: [AppComponent]
    })
    

    I suspect there is maybe some other way to 'register' the ArtistService so it stays loaded as a static instance? Is that possible via DI or is it necessary to create a static instance method manually?

    Update:
    Turns out that the above code does work. I was looking in the wrong place along with a logic error that caused data not to cache correctly.

    The above code works and assigning the service in the providers section of the top level AppModule is the key to making the parent reference stay loaded for the duration of the AppComponent. which effectively stays loaded for the lifetime of the app providing the Singleton instance.

    To get a transient instance you can declare the providers meta tag and the service name on the actual component which will then create the service whenever the component is loaded/re-loaded.

  • ouah
    ouah almost 8 years
    Hmmm... it's not working for me. The service constructor fires on every injection into the ArtistDisplayComponent.
  • micronyks
    micronyks almost 8 years
    look I have added working link which shows shared service.
  • ouah
    ouah almost 8 years
    Ok do I double checked and it is indeed working. Operator error on my part - I was looking at the wrong console.log() :-)
  • GhostCat
    GhostCat over 7 years
    Hint: i read your answer three times and i am still not sure what you try to communicate. If english is not your first language: go for short Subject Verb Object senteces. Focus on writing human-readable text!
  • Tek
    Tek over 7 years
    Well I still have no idea how you show it's singleton when you have single Component. In order to check if it's a singleton or not is to have 2 components injecting same service.
  • micronyks
    micronyks over 7 years
    providing providers:[service], in appmodule makes it singleton. if you inject it in different component individually then component will have its own instance. so in order to make it singleton you have to add it in ngModule's of appModule or you can create a coremodule(read more at official site) @Tek
  • praHoc
    praHoc about 7 years
    you save me! I have component1 is not injected the service and the component2 is injected the service. and I don't get the singleton until I removed the service from component2 provider. thank!!!