Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

415
Views
How do I create a singleton service in Angular 2?

I've read that injecting when bootstrapping should have all children share the same instance, but my main and header components (main app includes header component and router-outlet) are each getting a separate instance of my services.

I have a FacebookService which I use to make calls to the facebook javascript api and a UserService that uses the FacebookService. Here's my bootstrap:

bootstrap(MainAppComponent, [ROUTER_PROVIDERS, UserService, FacebookService]);

From my logging it looks like the bootstrap call finishes, then I see the FacebookService then UserService being created before the code in each of the constructors runs, the MainAppComponent, the HeaderComponent and the DefaultComponent:

enter image description here

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

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 {
}
  • https://angular.io/guide/singleton-services
  • https://angular.io/guide/providers

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.

over 4 years ago · Santiago Trujillo Report

0

Jason is completely right! It's caused by the way dependency injection works. It's based on hierarchical injectors.

There are several injectors within an Angular2 application:

  • The root one you configure when bootstrapping your application
  • An injector per component. If you use a component inside another one. The component injector is a child of the parent component one. The application component (the one you specify when boostrapping your application) has the root injector as parent one).

When Angular2 tries to inject something in the component constructor:

  • It looks into the injector associated with the component. If there is matching one, it will use it to get the corresponding instance. This instance is lazily created and is a singleton for this injector.
  • If there is no provider at this level, it will look at the parent injector (and so on).

So if you want to have a singleton for the whole application, you need to have the provider defined either at the level of the root injector or the application component injector.

But Angular2 will look at the injector tree from the bottom. This means that the provider at the lowest level will be used and the scope of the associated instance will be this level.

See this question for more details:

  • What's the best way to inject one service into another in angular 2 (Beta)?
over 4 years ago · Santiago Trujillo Report

0

I know angular has hierarchical injectors like Thierry said.

But I have another option here in case you find a use-case where you don't really want to inject it at the parent.

We can achieve that by creating an instance of the service, and on provide always return that.

import { provide, Injectable } from '@angular/core';
import { Http } from '@angular/core'; //Dummy example of dependencies

@Injectable()
export class YourService {
  private static instance: YourService = null;

  // Return the instance of the service
  public static getInstance(http: Http): YourService {
    if (YourService.instance === null) {
       YourService.instance = new YourService(http);
    }
    return YourService.instance;
  }

  constructor(private http: Http) {}
}

export const YOUR_SERVICE_PROVIDER = [
  provide(YourService, {
    deps: [Http],
    useFactory: (http: Http): YourService => {
      return YourService.getInstance(http);
    }
  })
];

And then on your component you use your custom provide method.

@Component({
  providers: [YOUR_SERVICE_PROVIDER]
})

And you should have a singleton service without depending on the hierarchical injectors.

I'm not saying this is a better way, is just in case someone has a problem where hierarchical injectors aren't possible.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!