Dependency Injection @ AngularJS
-
Upload
ran-mizrahi -
Category
Technology
-
view
2.391 -
download
1
description
Transcript of Dependency Injection @ AngularJS
Dependency Injection@ AngularJS
Ran Mizrahi (@ranm8)Open Source Dpt. Leader @ CodeOasis
Monday, September 9, 13
About CodeOasis
• CodeOasis specializes in cutting-edge web solutions.
• Large variety of customers (from startups to enterprises).
• We LOVE JavaScript (-:
• Technologies we love:
• Symfony2• AngularJS • nodeJS • HTML5• CSS3
• Our Microsoft department works with C#, WPF, etc.
Monday, September 9, 13
What is Dependency Injection???
Monday, September 9, 13
The Problemfunction SessionStore() {}
SessionStore.prototype = { set: function(name, value) { window.localStorage.setItem(name, value); }, get: function(name) { return window.localStorage.getItem(name); }}
function User() { this.sessionStore = new SessionStore();}
User.prototype = { setSession: function(session) { this.sessionStore.set('session', session); }, getSession: function() { return this.sessionStore.get('session'); }}
Monday, September 9, 13
The ProblemEverything goes well and the code is working.But now we have to change the session name...
We can use a global variable:sessionName = 'newSessionName';
function User() { this.sessionStore = new SessionStore();}
// ...
Maybe we should hard-coded pass it to the store:function User() { this.sessionStore = new SessionStore('newSessionName');}
// ...
Monday, September 9, 13
The Problem
How would you change the entire SessionStore implementation?
CookiesServer
...
function User() { this.sessionStore = registry.get('SessionStore');}
// ...
Should we use some global registry object??
How would we test the User??
Monday, September 9, 13
The Problem
All those solutions are bad because:
• Couples code to one implementation.
• Hard to configure
• Cannot change the implementation without changing the User prototype.
• Untestable code unless you monkey patch it.
Monday, September 9, 13
Dependency Injection
Dependency injection is a software design pattern that allows the
removal of hard-coded dependencies and makes it possible
to change them.-- Wikipedia
Monday, September 9, 13
Dependency Injection To The Rescue!
Instead of instantiating the SessionStore within the User...
function User(sessionStore) { this.sessionStore = sessionStore;}
// ...
var user = new User(new SessionStore());
JUST INJECT IT!!!
Monday, September 9, 13
Advantages Of Using DI
Use different session store strategies...
function User(sessionStore) { this.sessionStore = sessionStore;}
// ...
var user = new User(new CookieSessionStore());
Monday, September 9, 13
Advantages Of Using DI
Configuration becomes easy...
function User(sessionStore) { this.sessionStore = sessionStore;}
// ...
var user = new User(new SessionStore('mySessionName'));
Monday, September 9, 13
Advantages Of Using DI
Now we can easily mock the SessionStore (for testing purposes)...
function User(sessionStore) { this.sessionStore = sessionStore;}
// ...
var user = new User(new MockSessionStore());
Monday, September 9, 13
All those things makes our code
MAINTAINABLEbecause we’ve..
Less codeExtensibleTestable
Monday, September 9, 13
But How To Scale It?!!?!?
But what if we have a slightly more complex application..
And we do that in many different places around our application:
var user = new User(new SessionStore(new SomeThirdParty(jQuery), new Http(new Thing())), new Something());
//....
var user = new User(new SessionStore(new SomeThirdParty(jQuery), new Http(new Thing())), new Something());
//....
var user = new User(new SessionStore(new SomeThirdParty(jQuery), new Http(new Thing())), new Something());
Monday, September 9, 13
Don’t worry!
Monday, September 9, 13
DI Container To The Rescue
Monday, September 9, 13
DI Container (e.g. Injector, Provider)
• Instantiates objects and their dependencies on demand.
• Allows to configure objects before instantiation.
• Can instantiate new objects on demand or provide existing ones from cache.
• The objects must never know they are being managed by the container.
• A container should be able to manage any object.
Monday, September 9, 13
AngularJS DI
Monday, September 9, 13
How The DI Injector Works?!
• Angular inject the requested service by the function argument names.
• Can also be done with an array.
• Once requested Angular’s injector would instantiate the requested service and inject it.
angular.module('myModule') .controller('MyCtrl', MyCtrl); function MyCtrl($http) { $http.get('http://google.com').then(getTheMonkey); }
Monday, September 9, 13
The Array Notation
• Allows minifiers to preserve argument names for the dependency injection to work with.
• More flexible - Separates dependency declaration from your unit.
angular.module('myModule') .controller('MyCtrl', ['$http', MyCtrl]); function MyCtrl($http) { $http.get('http://google.com').then(getTheMonkey); }
Monday, September 9, 13
Changing The Implementationangular.module('myModule') .controller('MyCtrl', ['myHttp', MyCtrl]) .factory('myHttp', ['$q', myHttp]); function myHttp($q) { return { get: function() { var defer = $q.defer(); // Do something with XHR and return a promise... return defer.promise; } };}
function MyCtrl($http) { $http.get('http://google.com').then(someCallback); }
• Changes the implementation by changing only the array notation.
• Angular’s injector instantiates the dependencies of each dependency.
Monday, September 9, 13
How Do I Use It?
Monday, September 9, 13
Service/Factory
A service is the Angular way of exposing objects within the $injector.
• Can have multiple dependencies that will be injected when invoked.
angular.module('myModule') .service('myHttp', ['$q', myHttp]); function myHttp($q) { this.get = function() { var defer = $q.defer(); // Do something with XHR and return a promise... return defer.promise; };}
Monday, September 9, 13
Factory
Shorthand for registering services without a constructor function (assigned to $get property directly).
angular.module('myModule') .factory('myHttp', ['$q', myHttp]);
function myHttp($q) { return { get: function() { var defer = $q.defer(); // Do something with XHR and return a promise... return defer.promise; } };}
Monday, September 9, 13
Provider
Registers a provider to a service.
• Allows the save configuration state to the service.
• Only constants can be injected.
• The provider is a constructor function.
• $get is a function that returns the actual service.
Monday, September 9, 13
Provider
angular.module('myModule') .provider('myHttp', myHttp); function myHttp() { var baseUrl; this.baseUrl = function(value) { if (!value) { return baseUrl; } baseUrl = value; }; this.$get = ['$q', function() { // myHttp service implementation... }];}
Monday, September 9, 13
Configuration Phase vs. Run Phase Configuration Phase
Run Phase
• Runs before any service was instantiated.
• Only providers can be injected.
• Each provider is injected with the “Provider” suffix (e.g. $locationProvider)
• Allows to purely configure the services state.
• Services state should be not be changed now (already configured during run phase).
• Providers now cannot be injected.
Monday, September 9, 13
Config
Use the service providers to configure the services state during the config phase to the run phase.
angular.module('myModule') .config(['myHttpProvider', '$locationProvider', appConfig]);
function appConfig(myHttpProvider, $locationProvider) { // Configure app to use HTML5 History API.. $locationProvider.html5Mode(true); // Configure my service baseUrl.. myHttpProvider.baseUrl('http://www.example.com');}
Monday, September 9, 13
Value
Value is a shorthand to register a simple value as a service.
angular.module('myModule') .value('myHttp', 'some string');
Monday, September 9, 13
Constant
Constant is the same as value, but unlike value it can be injected to configuration function
angular.module('myModule') .constant('someConstant', '123');
Monday, September 9, 13
Angular’s DI In Testingdescribe('myHttp', function() {
var mockQ = { then: function(){}
}, http; beforeEach(module(function($provide) { $provide.value('$q', mockQ); })); beforeEach(inject(function(myHttp) { http = myHttp; })); describe('#get()', function() { it('should return a promise', function() { // test your code here }); });});
Monday, September 9, 13
Questions?Thank you!
Monday, September 9, 13