Welcome to this tutorial on singleton services in Angular!
In this tutorial, you will learn what singleton services are, how to create and use them in your Angular applications, and when to use them.
Table of Contents
What is Singleton Service in Angular ?
Angular singleton service is a service that is instantiated only once and shared among all components in the application.
This means that all components in the application that inject the same singleton service will receive the same instance of the service.
Angular Singleton services are useful for storing and sharing application-wide data and logic, such as user authentication or application settings.
They can also be used to avoid unnecessary service instantiations, which can improve the performance of your application.
How to create Singleton Service in Angular ?
There are two main ways to create a singleton service in Angular:
Using providedIn property
You can use the providedIn
property of the @Injectable
decorator to specify that the service should be provided in the root injector or in a specific module.
This will create a singleton service that is available to all components in the application or in a specific module, depending on how you configure the providedIn
property.
Here is an example of a singleton service provided in the root injector:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class MyService {
// service methods and properties go here
}
And here is an example of a singleton service provided in a specific module:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'myModule'
})
export class MyService {
// service methods and properties go here
}
Using a provider in a module
Another way to create an angular singleton service is to use a provider in a module.
You can do this by adding a provider to the providers array of the @NgModule
decorator. This will create a singleton service that is available to all components in the module.
Here is an example of a singleton service provided using a provider in a module:
import { NgModule } from '@angular/core';
import { MyService } from './my.service';
@NgModule({
providers: [MyService]
})
export class MyModule { }
In this example, the MyService
service will be available to all components in the MyModule
module.
Angular Singleton Service Example
Here is a basic example of a singleton service in Angular that stores and retrieves a user’s name:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UserService {
private userName: string;
constructor() { }
setUserName(name: string) {
this.userName = name;
}
getUserName(): string {
return this.userName;
}
}
To use this service in a component, you can inject it into the component’s constructor and use its methods to set and retrieve the user’s name:
import { UserService } from './user.service';
@Component({
// component metadata goes here
})
export class MyComponent {
constructor(private userService: UserService) { }
setUserName(name: string) {
this.userService.setUserName(name);
}
getUserName(): string {
return this.userService.getUserName();
}
}
In this example, the UserService
is a singleton service that is shared among all components in the application, and all components that inject the UserService
will receive the same instance of the service.
This means that any component can use the setUserName
and getUserName
methods to set and retrieve the user’s name, and the value will be the same for all components.
Singleton Service in Lazy Loaded Module
You cannot use both approaches (using provideIn property & using provider in module) to create a singleton service in a lazy-loaded module.
If you use the providedIn
property in the service to specify that the service should be provided at the root level, it will be available throughout the application, including in the lazy-loaded module.
@Injectable({ providedIn: 'root' })
export class myService {
//your lazy service
}
However, if you provide the service in the lazy-loaded module using the providers
array in the @NgModule
decorator, the service will only be available in the lazy-loaded module and not outside of it.
@NgModule({
imports: [],
declarations: [myComponent],
providers: [myService]
})
export class LazyModule {}
In this case, the service will not be a singleton service and a new instance will be created for each component that uses it.
To create a singleton service that is available throughout the application, including in the lazy-loaded module, you should provide the service at the root level using the providedIn
property or the providers
array in the root module.
Using Factory to prevent problems ( use case )
There can be a problem with using a singleton service in a lazy-loaded module if the service needs to perform some initialization that requires the module to be loaded first.
For example, let’s say you have a service that needs to load some data from a remote API when it is initialized.
If you provide the service at the root level, it will be initialized as soon as the application starts, even before the lazy-loaded module is loaded.
This can cause problems if the service needs to wait for the lazy-loaded module to be loaded before it can initialize itself.
To solve this problem, you can use a factory function to create the service instance when the lazy-loaded module is actually loaded.
This way, you can ensure that the service is initialized only when the module is loaded, and the initialization can depend on the module being present.
Here is an example of how you can use a factory function to create a singleton service in a lazy-loaded module:
import { NgModule, Injector } from '@angular/core';
import { MyComponent } from './my.component';
import { MyService } from './my.service';
export function createMyService(injector: Injector) {
return new MyService(injector);
}
@NgModule({
declarations: [MyComponent],
providers: [
{
provide: MyService,
useFactory: createMyService,
deps: [Injector]
}
]
})
export class MyLazyLoadedModule { }
This way, the MyService
will be a singleton service that is shared by all components in the application, including those in the lazy-loaded module.
The service will be initialized only when the lazy-loaded module is actually loaded, and the initialization can depend on the module being present.
References and Links
Here are more related references and links that discuss the same subject:
- Angular Documentation
- Dependency injection in Angular
- How to use Services in Angular ?
- How to use Providers in Angular ?
- Using Injector , @Injectable & @Inject in Angular
- How to create a singleton service in Angular ?
- Using provideIn root , any & platform in Angular ?
- How to use ViewProviders in Angular ?
- Using @Self , @SkipSelf & Optional Decorators in Angular
- How to use APP_INITIALIZER provider in Angular ?