In AngularJS, services are the preferred way to manage and share application state across different components like controllers, directives, and filters. While $rootScope
can be used for global state, services provide a more structured, maintainable, and scalable approach.
1. Why Use Services for Shared State?
Using services instead of $rootScope
has several advantages:
Encapsulation – Keeps data and logic inside a reusable component.
Reusability – The same service can be injected into multiple components.
Performance Optimization – Reduces unnecessary event listeners and watchers.
Testability – Services can be easily tested with unit tests.
Avoids Scope Pollution – Prevents global state pollution like $rootScope
.
2. Creating a Shared State Service
AngularJS provides multiple ways to create services:
- Factory (
.factory
) - Service (
.service
) - Provider (
.provider
)
The most common approach is using a Factory.
Example: Creating a Shared Service
app.factory('SharedStateService', function() {
var sharedData = {
user: null,
isAuthenticated: false
};
return {
getUser: function() {
return sharedData.user;
},
setUser: function(user) {
sharedData.user = user;
sharedData.isAuthenticated = !!user;
},
isAuthenticated: function() {
return sharedData.isAuthenticated;
}
};
});
3. Injecting the Service in Controllers
Once the service is created, it can be injected into multiple controllers.
Example: Using the Service in a Login Controller
app.controller('LoginController', function($scope, SharedStateService) {
$scope.login = function() {
// Simulating login
SharedStateService.setUser({ name: "John Doe", email: "john@example.com" });
console.log("User logged in:", SharedStateService.getUser());
};
});
Example: Using the Service in Another Controller
app.controller('DashboardController', function($scope, SharedStateService) {
$scope.user = SharedStateService.getUser();
$scope.isAuthenticated = SharedStateService.isAuthenticated();
});
4. Sharing Data Between Components
Since services in AngularJS follow the singleton pattern, any data stored in the service is automatically available across different parts of the application.
Example: Accessing Data in a View
<div ng-controller="DashboardController">
<p ng-if="isAuthenticated">Welcome, {{ user.name }}!</p>
</div>
5. Updating Shared State Dynamically
You can update the state dynamically, and it will be reflected in all controllers using the service.
Example: Logging Out
$scope.logout = function() {
SharedStateService.setUser(null);
};
This logs out the user, and all components accessing SharedStateService
will see the update.
6. Using $rootScope.$broadcast()
for Updates
In some cases, you may need to notify all components about a state change.
Example: Broadcasting an Event on Login
app.factory('SharedStateService', function($rootScope) {
var sharedData = { user: null, isAuthenticated: false };
return {
setUser: function(user) {
sharedData.user = user;
sharedData.isAuthenticated = !!user;
$rootScope.$broadcast('userUpdated', sharedData);
},
getUser: function() {
return sharedData.user;
}
};
});
Listening for Changes in a Controller
$scope.$on('userUpdated', function(event, data) {
console.log("User state updated:", data);
});
7. Best Practices for Using Services for Shared State
Use Services Instead of $rootScope
for Shared Data
$rootScope
should be reserved for event broadcasting.- Services provide a structured and modular approach.
Use Factory Over Service
- Factories return an object, making it easier to manage state.
- Services use
this
, which can be harder to debug.
Keep State Immutable When Possible
- Avoid directly modifying shared data from multiple controllers.
- Use functions to modify the state.
Clear State on Logout
- Reset shared data when the user logs out to avoid stale data.
8. Alternative: Using $cacheFactory
for Storing Shared Data
If you need caching along with shared state, $cacheFactory
can be used.
Example
app.factory('CacheService', function($cacheFactory) {
return $cacheFactory('sharedCache');
});
Storing Data
CacheService.put('user', { name: 'John Doe' });
Retrieving Data
var user = CacheService.get('user');