In AngularJS, services are used to share data and logic across different components. By default, services in AngularJS are singletons, meaning they are instantiated only once and shared across the application.
This guide will cover:
What is a Singleton Service?
Different ways to create a Singleton Service in AngularJS
Step-by-step implementation with examples
1. What is a Singleton Service?
A singleton service is a service that is created only once and shared across all components of the application. It helps in:
- Data Sharing – Stores and manages data that can be accessed by multiple controllers.
- State Management – Keeps application-wide states, like user authentication or settings.
- Performance Optimization – Reduces memory usage by avoiding multiple instances.
2. Creating a Singleton Service in AngularJS
AngularJS provides multiple ways to create services. All of them follow the singleton pattern when registered with Angular’s dependency injection.
A. Using service()
(Recommended for OOP Style)
The .service()
method is a constructor function. It is instantiated using the new
keyword.
Example: Singleton Service Using .service()
app.service('UserService', function() {
this.user = {}; // Shared user object
this.setUser = function(userData) {
this.user = userData;
};
this.getUser = function() {
return this.user;
};
});
Usage in Controllers:
app.controller('MainCtrl', function($scope, UserService) {
$scope.setUser = function() {
UserService.setUser({ name: "John", role: "Admin" });
};
});
app.controller('ProfileCtrl', function($scope, UserService) {
$scope.user = UserService.getUser(); // Same instance as in MainCtrl
});
Why?
- Easy to understand and maintain.
- Uses
this
to define properties and methods.
B. Using factory()
(Recommended for Complex Logic)
The .factory()
method returns an object or function, making it flexible for more complex logic.
Example: Singleton Service Using .factory()
app.factory('AuthService', function() {
let authData = { isAuthenticated: false };
return {
login: function() {
authData.isAuthenticated = true;
},
logout: function() {
authData.isAuthenticated = false;
},
isLoggedIn: function() {
return authData.isAuthenticated;
}
};
});
Usage in Controllers:
app.controller('LoginCtrl', function($scope, AuthService) {
$scope.login = function() {
AuthService.login();
};
});
app.controller('DashboardCtrl', function($scope, AuthService) {
$scope.isLoggedIn = AuthService.isLoggedIn(); // Uses the same instance
});
Why?
- Encapsulates logic in an object and returns it.
- More flexible than
.service()
because it allows private variables.
C. Using provider()
(For Configurable Services)
The .provider()
method is useful when the service needs configurable options.
Example: Singleton Service Using .provider()
app.provider('ConfigService', function() {
let settings = { theme: 'light' };
this.setTheme = function(theme) {
settings.theme = theme;
};
this.$get = function() {
return {
getTheme: function() {
return settings.theme;
}
};
};
});
// Configuring the provider
app.config(function(ConfigServiceProvider) {
ConfigServiceProvider.setTheme('dark');
});
Usage in Controllers:
app.controller('ThemeCtrl', function($scope, ConfigService) {
$scope.theme = ConfigService.getTheme(); // Will return 'dark'
});
Why?
- Allows configuration during app initialization.
- Best suited for global settings like themes, API URLs, etc.
3. Singleton Behavior Explained
Why are AngularJS Services Singletons?
AngularJS instantiates a service only once and shares the same instance throughout the application.
If multiple controllers use the same service, they all refer to the same instance.
This allows data sharing and state persistence across the app.
4. Best Practices for Singleton Services
🔹 Use .service()
for simple data sharing and OOP-style instances.
🔹 Use .factory()
when more complex logic or private variables are needed.
🔹 Use .provider()
when you need configurable services.
🔹 Avoid using $rootScope
for global state management; instead, use a singleton service.
🔹 If dealing with asynchronous data, use $q
and cache data to avoid redundant API calls.
Example: Caching API Responses in Singleton Service
app.factory('DataService', function($http, $q) {
let cache = null;
return {
getData: function() {
if (cache) return $q.resolve(cache); // Return cached data
return $http.get('/api/data').then(function(response) {
cache = response.data; // Store data in cache
return cache;
});
}
};
});
Why?
- Prevents multiple API calls for the same data.
- Improves performance by using cached results.