- Angular JS Tutorial
- AngularJS Home
- AngularJS Introduction
- AngularJS Expressions
- AngularJS Directives
- AngularJS Modules
- AngularJS Controllers
- AngularJS Scopes
- AngularJS Data Binding
- AngularJS Services
- AngularJS HTTP
- AngularJS Filters
- AngularJS Forms
- AngularJS Validation
- AngularJS DOM Manipulation
- AngularJS Select
- AngularJS Tables
- AngularJS Events
- AngularJS Routing
- AngularJS Includes
- AngularJS Animations
- AngularJS Dependency Injection
- AngularJS API
- AngularJS Deployment
AngularJS Dependency Injection
Dependency Injection (DI) is one of the most powerful features of AngularJS. At its core, it is a design pattern that implements "Inversion of Control." Instead of a component (like a controller) being responsible for creating its own dependencies—such as fetching data from an API or logging errors—the dependencies are "injected" into it by the AngularJS framework. This approach makes your code significantly more modular, easier to read, and much simpler to test because you can swap out real services for "mock" ones during testing.
Key Concepts of AngularJS Dependency Injection
- Injector: This is the engine room. It is the service locator responsible for looking up dependency definitions, instantiating them when needed, and handing them over to the components that requested them.
- Providers: These are the blueprints. Every service in AngularJS is created by a provider. While you usually use helper methods like
.service(), they are actually just wrappers for the more complex$provideservice. - Services: Defined using the
.service()method. It is treated as a constructor function and instantiated with thenewkeyword. It is a singleton, meaning only one instance exists throughout your app's lifecycle. - Factories: Defined using the
.factory()method. Unlike a service, a factory is just a function that returns an object. It is more common in the community because it offers more flexibility in how the object is created. - Values: Used for simple configuration or strings that might change. They can be injected into controllers and services, but they cannot be injected into the module configuration phase.
- Constants: Similar to values, but with one major difference: they are available during the
.config()phase of your application, making them perfect for global settings like API base URLs.
.service() and .factory(). Remember: a Service is a constructor (uses this), while a Factory is a function that returns an object.
How Dependency Injection Works in AngularJS
Step 1: Define a Service/Factory
To use DI, you first need to register your logic within an AngularJS module. Let's look at how we might create a simple notification system using different methods.
Example: Defining a Service
Use this when you prefer an object-oriented style with the this keyword.
angular.module('myApp', [])
.service('notificationService', function() {
this.message = "System Ready";
this.log = function(msg) {
console.log("Log: " + msg);
};
});
Example: Defining a Factory
Use this for more complex logic where you want to return a specific object literal.
angular.module('myApp', [])
.factory('apiFactory', function($http) {
return {
getUser: function(userId) {
return $http.get('/api/users/' + userId);
}
};
});
Example: Defining a Value
angular.module('myApp', [])
.value('appSettings', {
version: '1.0.4',
theme: 'dark'
});
Step 2: Inject Dependencies into a Controller
Once registered, you simply list the name of the dependency as an argument in your controller function. AngularJS sees the name and automatically provides the correct instance.
Example: Injecting a Service into a Controller
angular.module('myApp')
.controller('UserProfileCtrl', function($scope, apiFactory, notificationService) {
notificationService.log("Loading profile...");
apiFactory.getUser(123).then(function(response) {
$scope.user = response.data;
});
});
Step 3: Use Dependency Injection in Directives and Services
Dependency Injection isn't just for controllers. You can (and should) inject services into other services or custom directives to keep your logic DRY (Don't Repeat Yourself).
Example: Injecting a Service into a Directive
angular.module('myApp')
.directive('userStatus', function(notificationService) {
return {
restrict: 'E',
template: '<button ng-click="check()">Check Status</button>',
link: function(scope) {
scope.check = function() {
notificationService.log("Status button clicked!");
};
}
};
});
Step 4: Using Constants and Values
Constants are essential for values that shouldn't change and need to be accessed even before the app fully starts (the config phase).
Example: Defining a Constant
angular.module('myApp', [])
.constant('API_CONFIG', {
baseUrl: 'https://api.myapp.com/v1',
timeout: 5000
});
.constant() for environment variables like API endpoints and .value() for data that might be updated by the application during its execution.
Step 5: Multiple Dependencies and DI Injection Syntax
In a real-world project, your code will eventually be "minified" to save space. Minification turns variables like $scope and myService into single letters like a and b. This breaks the standard DI because AngularJS won't know what a is.
To fix this, we use Array Annotation.
Example: Safe Injection Syntax
angular.module('myApp', [])
.controller('myCtrl', ['$scope', 'notificationService', 'apiFactory', function($scope, notificationService, apiFactory) {
// Logic goes here...
}]);
Benefits of Dependency Injection in AngularJS
- Modularity: Your app becomes a collection of small, focused pieces. You can write a service once and use it in ten different controllers.
- Testability: This is the biggest win. If a controller depends on
$http, you can inject a "mock" version during a unit test that doesn't actually make network calls, allowing for fast, reliable tests. - Flexibility: If you need to change how data is saved (e.g., switching from LocalStorage to a database), you only change the service. The controllers using it never need to know the implementation changed.
- Reusability: Well-written services can even be moved between different AngularJS projects with minimal changes.
- Lazy Loading: AngularJS only creates the instance of a service when someone actually asks for it, which helps keep the initial memory footprint lower.
Summary
Dependency Injection is the glue that holds an AngularJS application together. By mastering services, factories, and the array notation for minification, you ensure your code is professional, scalable, and easy to maintain. It moves the responsibility of managing "how objects are created" away from your business logic, allowing you to focus on building features rather than managing object lifecycles.