Angular 2 - Singleton Services?
Asked Answered
V

4

8

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.

Valerio answered 2/9, 2016 at 4:38 Comment(0)
U
3

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 { }
Unwinking answered 2/9, 2016 at 4:44 Comment(5)
Hmmm... it's not working for me. The service constructor fires on every injection into the ArtistDisplayComponent.Valerio
look I have added working link which shows shared service.Unwinking
Ok do I double checked and it is indeed working. Operator error on my part - I was looking at the wrong console.log() :-)Valerio
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.Marius
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) @MariusUnwinking
K
3

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

Kootenay answered 7/1, 2017 at 20:0 Comment(1)
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!Boorman
B
2

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

Blondell answered 28/2, 2017 at 9:24 Comment(0)
M
1

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.

Marius answered 10/1, 2017 at 10:19 Comment(1)
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!!!Philippine

© 2022 - 2024 — McMap. All rights reserved.