This document discusses dependency injection (DI) in AngularJS. It explains that DI allows high-level modules to depend on low-level abstractions rather than implementations. It then covers the different ways to define providers in AngularJS, including using the $provide service, as well as factories, services, values, and constants. It also discusses decorators as another way to modify existing services. The document provides recipes for when to use each provider type and concludes with some additional facts about injectors and ensuring scripts are in the proper order.
3. Dependency Injection
High-level modules should not depend on
low-level modules. Both should depend
on abstractions.
Abstractions should not depend on details.
Details should depend on abstractions.
4. DI in a Nutshell
create the dependency
look up the dependency
have the dependency injected
6. Wiki: The provider
The $provide service is responsible for telling Angular how
to create new injectable things; these things are
called services. Services are defined by things
called providers, which is what you're creating when you
use $provide. Defining a provider is done via
the provider method on the $provide service, and you can
get hold of the $provide service by asking for it to be injected
into an application's config function.
https://github.com/angular/angular.js/wiki/Understanding-Dependency-Injection
7.
8. How do we usually inject?
myApp.service('alerter', function () {
http://jsfiddle.net/ae87/9x7Aq/2/
this.sayHello = function(){
alert('Hello! ');
}
this.sayGoodbye = function(){
alert('Goodbye!');
}
});
16. Provider way
function provider(name, provider_) {
assertNotHasOwnProperty(name, 'service');
if (isFunction(provider_) || isArray(provider_)) {
provider_
= providerInjector.instantiate(provider_);
}
if (!provider_.$get)
return providerCache[name + providerSuffix]
= provider_;
}
17. Factory way
function factory(name, factoryFn) {
return provider(
name,
{
$get: factoryFn
});
}
18. Service way
function service(name, constructor) {
return factory(
name,
[
'$injector',
function ($injector) {
return $injector.instantiate(constructor);
}
]);
}
19. Value way
function value(name, val) {
return factory(
name,
valueFn(val)
);
}
function valueFn(value) {
return function () {
return value;
};
}
20. Constant way
function constant(name, value) {
assertNotHasOwnProperty(name, 'constant');
providerCache[name] = value;
instanceCache[name] = value;
}
27. Service Recipe
Utility functions via public API
Non-new-able stuff
Works better for objects of custom type
service(class)
– registers a constructor function,
class that will be wrapped in
a service provider object
28. Factory Recipe
Exposing public API
Constructors via new-able functions
Can produce JavaScript primitives and functions
factory(fn)
– registers a service factory
function, that will be wrapped
in a service provider object
29. Provider Recipe
Configurable stuff
You don't need it unless you are building a
reusable piece of code that needs global
configuration
provider(provider)
– registers a service provider
with the $injector
30. Value Recipe
Exposing static values and constants
value(obj)
– registers a value/object that
can only be accessed by
services, not providers
31. Constant Recipe
Exposing compile time static values and
constants
constant(obj)
– registers a value/object
that can be accessed by
providers and services
33. Decorator way
function decorator(serviceName, decorFn) {
var origProvider = providerInjector
.get(serviceName + providerSuffix),
orig$get = origProvider.$get;
origProvider.$get = function () {
var origInstance = instanceInjector
.invoke(orig$get, origProvider);
return instanceInjector.invoke(
decorFn, null,
{ $delegate: origInstance });
};
}
34. Know-how
app.config(function ($provide) {
$provide.decorator('$log', function ($delegate) {
// save the original function
var _log = $delegate.log;
// replace the original behavior
$delegate.log = function (msg) {
_log(msg);
alert(msg);
};
return $delegate;
});
});
http://plnkr.co/edit/imqmvUfk4oWWuwg75sP1?p=preview
37. Injector: Why
Feel the power of DI
Control the injection real-time
Access DI container from outside of your app
Primary usage - testing
38. Injector: How
function MyController($scope, $injector) {
$scope.doSomething = function(someServiceName) {
// someService contains the name of a service
var service = $injector.get(someServiceName);
service.do();
};
}