Angular 2 - Singleton Services?

Rick Strahl picture Rick Strahl · Sep 2, 2016 · Viewed 17.4k times · Source

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.

Answer

Nikhil Shah picture Nikhil Shah · Sep 2, 2016

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 { }