How do I create a singleton service in Angular 2?

Update (Angular 6 +)

The recommended way to create a singleton service has changed. It is now recommended to specify in the @Injectable decorator on the service that it should be provided in the ‘root’. This makes a lot of sense to me and there’s no need to list all the provided services in your modules at all anymore. You just import the services when you need them and they register themselves in the proper place. You can also specify a module so it will only be provided if the module is imported.

@Injectable({
  providedIn: 'root',
})
export class ApiService {
}

Update (Angular 2)

With NgModule, the way to do it now I think is to create a ‘CoreModule’ with your service class in it, and list the service in the module’s providers. Then you import the core module in your main app module which will provide the one instance to any children requesting that class in their constructors:

CoreModule.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ApiService } from './api.service';

@NgModule({
    imports: [
        CommonModule
    ],
    exports: [ // components that we want to make available
    ],
    declarations: [ // components for use in THIS module
    ],
    providers: [ // singleton services
        ApiService,
    ]
})
export class CoreModule { }

AppModule.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AppComponent } from './app.component';
import { CoreModule } from './core/core.module';

@NgModule({
    declarations: [ AppComponent ],
    imports: [
        CommonModule,
        CoreModule // will provide ApiService
    ],
    providers: [],
    bootstrap: [ AppComponent ]
})
export class AppModule { }

Original Answer

If you list a provider in bootstrap(), you don’t need to list them in your component decorator:

import { ApiService } from '../core/api-service';

@Component({
    selector: 'main-app',
    templateUrl: '/views/main-app.html',
    // DO NOT LIST PROVIDERS HERE IF THEY ARE IN bootstrap()!
    // (unless you want a new instance)
    //providers: [ApiService]
})
export class MainAppComponent {
    constructor(private api: ApiService) {}
}

In fact listing your class in ‘providers’ creates a new instance of it, if any parent component already lists it then the children don’t need to, and if they do they will get a new instance.

Leave a Comment