{ "id": "guide/singleton-services", "title": "Singleton services", "contents": "\n\n\n
\n mode_edit\n
\n\n\n
\n

Singleton serviceslink

\n

A singleton service is a service for which only one instance exists in an app.

\n

For a sample app using the app-wide singleton service that this page describes, see the\n showcasing all the documented features of NgModules.

\n

Providing a singleton servicelink

\n

There are two ways to make a service a singleton in Angular:

\n\n\n

Using providedInlink

\n

Beginning with Angular 6.0, the preferred way to create a singleton service is to set providedIn to root on the service's @Injectable() decorator. This tells Angular\nto provide the service in the application root.

\n\nimport { Injectable } from '@angular/core';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class UserService {\n}\n\n\n\n

For more detailed information on services, see the Services chapter of the\nTour of Heroes tutorial.

\n

NgModule providers arraylink

\n

In apps built with Angular versions prior to 6.0, services are registered NgModule providers arrays as follows:

\n\n@NgModule({\n ...\n providers: [UserService],\n ...\n})\n\n

If this NgModule were the root AppModule, the UserService would be a singleton and available\nthroughout the app. Though you may see it coded this way, using the providedIn property of the @Injectable() decorator on the service itself is preferable as of Angular 6.0 as it makes your services tree-shakable.

\n\n

The forRoot() patternlink

\n

Generally, you'll only need providedIn for providing services and forRoot()/forChild() for routing. However, understanding how forRoot() works to make sure a service is a singleton will inform your development at a deeper level.

\n

If a module defines both providers and declarations (components, directives, pipes),\nthen loading the module in multiple feature modules would duplicate the registration of the service. This could result in multiple service instances and the service would no longer behave as a singleton.

\n

There are multiple ways to prevent this:

\n\n
\n

Note: There are two example apps where you can see this scenario; the more advanced NgModules live example, which contains forRoot() and forChild() in the routing modules and the GreetingModule, and the simpler Lazy Loading live example. For an introductory explanation see the Lazy Loading Feature Modules guide.

\n
\n

Use forRoot() to\nseparate providers from a module so you can import that module into the root module\nwith providers and child modules without providers.

\n
    \n
  1. Create a static method forRoot() on the module.
  2. \n
  3. Place the providers into the forRoot() method.
  4. \n
\n\nstatic forRoot(config: UserServiceConfig): ModuleWithProviders<GreetingModule> {\n return {\n ngModule: GreetingModule,\n providers: [\n {provide: UserServiceConfig, useValue: config }\n ]\n };\n}\n\n\n\n

forRoot() and the Routerlink

\n

RouterModule provides the Router service, as well as router directives, such as RouterOutlet and routerLink. The root application module imports RouterModule so that the application has a Router and the root application components can access the router directives. Any feature modules must also import RouterModule so that their components can place router directives into their templates.

\n

If the RouterModule didn’t have forRoot() then each feature module would instantiate a new Router instance, which would break the application as there can only be one Router. By using the forRoot() method, the root application module imports RouterModule.forRoot(...) and gets a Router, and all feature modules import RouterModule.forChild(...) which does not instantiate another Router.

\n
\n

Note: If you have a module which has both providers and declarations,\nyou can use this\ntechnique to separate them out and you may see this pattern in legacy apps.\nHowever, since Angular 6.0, the best practice for providing services is with the\n@Injectable() providedIn property.

\n
\n

How forRoot() workslink

\n

forRoot() takes a service configuration object and returns a\nModuleWithProviders, which is\na simple object with the following properties:

\n\n

In the live example\nthe root AppModule imports the GreetingModule and adds the\nproviders to the AppModule providers. Specifically,\nAngular accumulates all imported providers\nbefore appending the items listed in @NgModule.providers.\nThis sequence ensures that whatever you add explicitly to\nthe AppModule providers takes precedence over the providers\nof imported modules.

\n

The sample app imports GreetingModule and uses its forRoot() method one time, in AppModule. Registering it once like this prevents multiple instances.

\n

You can also add a forRoot() method in the GreetingModule that configures\nthe greeting UserService.

\n

In the following example, the optional, injected UserServiceConfig\nextends the greeting UserService. If a UserServiceConfig exists, the UserService sets the user name from that config.

\n\nconstructor(@Optional() config?: UserServiceConfig) {\n if (config) { this._userName = config.userName; }\n}\n\n\n

Here's forRoot() that takes a UserServiceConfig object:

\n\nstatic forRoot(config: UserServiceConfig): ModuleWithProviders<GreetingModule> {\n return {\n ngModule: GreetingModule,\n providers: [\n {provide: UserServiceConfig, useValue: config }\n ]\n };\n}\n\n\n

Lastly, call it within the imports list of the AppModule. In the following\nsnippet, other parts of the file are left out. For the complete file, see the , or continue to the next section of this document.

\n\nimport { GreetingModule } from './greeting/greeting.module';\n@NgModule({\n imports: [\n GreetingModule.forRoot({userName: 'Miss Marple'}),\n ],\n})\n\n\n

The app displays \"Miss Marple\" as the user instead of the default \"Sherlock Holmes\".

\n

Remember to import GreetingModule as a Javascript import at the top of the file and don't add it to more than one @NgModule imports list.

\n

Prevent reimport of the GreetingModulelink

\n

Only the root AppModule should import the GreetingModule. If a\nlazy-loaded module imports it too, the app can generate\nmultiple instances of a service.

\n

To guard against a lazy loaded module re-importing GreetingModule, add the following GreetingModule constructor.

\n\nconstructor(@Optional() @SkipSelf() parentModule?: GreetingModule) {\n if (parentModule) {\n throw new Error(\n 'GreetingModule is already loaded. Import it in the AppModule only');\n }\n}\n\n\n

The constructor tells Angular to inject the GreetingModule into itself.\nThe injection would be circular if Angular looked for\nGreetingModule in the current injector, but the @SkipSelf()\ndecorator means \"look for GreetingModule in an ancestor\ninjector, above me in the injector hierarchy.\"

\n

By default, the injector throws an error when it can't\nfind a requested provider.\nThe @Optional() decorator means not finding the service is OK.\nThe injector returns null, the parentModule parameter is null,\nand the constructor concludes uneventfully.

\n

It's a different story if you improperly import GreetingModule into a lazy loaded module such as CustomersModule.

\n

Angular creates a lazy loaded module with its own injector,\na child of the root injector.\n@SkipSelf() causes Angular to look for a GreetingModule in the parent injector, which this time is the root injector.\nOf course it finds the instance imported by the root AppModule.\nNow parentModule exists and the constructor throws the error.

\n

Here are the two files in their entirety for reference:

\n\n \n\nimport { BrowserModule } from '@angular/platform-browser';\nimport { NgModule } from '@angular/core';\n\n/* App Root */\nimport { AppComponent } from './app.component';\n\n/* Feature Modules */\nimport { ContactModule } from './contact/contact.module';\nimport { GreetingModule } from './greeting/greeting.module';\n\n/* Routing Module */\nimport { AppRoutingModule } from './app-routing.module';\n\n@NgModule({\n imports: [\n BrowserModule,\n ContactModule,\n GreetingModule.forRoot({userName: 'Miss Marple'}),\n AppRoutingModule\n ],\n declarations: [\n AppComponent\n ],\n bootstrap: [AppComponent]\n})\nexport class AppModule { }\n\n\n\n \nimport { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';\n\nimport { CommonModule } from '@angular/common';\n\nimport { GreetingComponent } from './greeting.component';\nimport { UserServiceConfig } from './user.service';\n\n\n@NgModule({\n imports: [ CommonModule ],\n declarations: [ GreetingComponent ],\n exports: [ GreetingComponent ]\n})\nexport class GreetingModule {\n constructor(@Optional() @SkipSelf() parentModule?: GreetingModule) {\n if (parentModule) {\n throw new Error(\n 'GreetingModule is already loaded. Import it in the AppModule only');\n }\n }\n\n static forRoot(config: UserServiceConfig): ModuleWithProviders<GreetingModule> {\n return {\n ngModule: GreetingModule,\n providers: [\n {provide: UserServiceConfig, useValue: config }\n ]\n };\n }\n}\n\n\n\n

More on NgModuleslink

\n

You may also be interested in:

\n\n\n \n
\n\n\n" }