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.

Rick Strahl
  • 17,302
  • 14
  • 89
  • 134

4 Answers4

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 { }
micronyks
  • 54,797
  • 15
  • 112
  • 146
  • 6
    Hmmm... it's not working for me. The service constructor fires on every injection into the `ArtistDisplayComponent`. – Rick Strahl Sep 02 '16 at 04:47
  • look I have added working link which shows shared service. – micronyks Sep 02 '16 at 04:54
  • Ok do I double checked and it is indeed working. Operator error on my part - I was looking at the wrong console.log() :-) – Rick Strahl Sep 02 '16 at 07:30
  • 2
    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. – Tek Jan 09 '17 at 13:41
  • 7
    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 – micronyks Jan 09 '17 at 15:34
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

mukund patel
  • 1,039
  • 10
  • 31
  • 2
    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! – GhostCat Jan 07 '17 at 20:14
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

Abdeali Chandanwala
  • 8,449
  • 6
  • 31
  • 45
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.

Tek
  • 1,178
  • 1
  • 12
  • 22
  • 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!!! – praHoc Jun 01 '17 at 14:00