Transcript
Page 1: Dependency Injection @ AngularJS

Dependency Injection@ AngularJS

Ran Mizrahi (@ranm8)Open Source Dpt. Leader @ CodeOasis

Monday, September 9, 13

Page 2: Dependency Injection @ AngularJS

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

Page 3: Dependency Injection @ AngularJS

What is Dependency Injection???

Monday, September 9, 13

Page 4: Dependency Injection @ AngularJS

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

Page 5: Dependency Injection @ AngularJS

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

Page 6: Dependency Injection @ AngularJS

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

Page 7: Dependency Injection @ AngularJS

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

Page 8: Dependency Injection @ AngularJS

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

Page 9: Dependency Injection @ AngularJS

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

Page 10: Dependency Injection @ AngularJS

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

Page 11: Dependency Injection @ AngularJS

Advantages Of Using DI

Configuration becomes easy...

function User(sessionStore) { this.sessionStore = sessionStore;}

// ...

var user = new User(new SessionStore('mySessionName'));

Monday, September 9, 13

Page 12: Dependency Injection @ AngularJS

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

Page 13: Dependency Injection @ AngularJS

All those things makes our code

MAINTAINABLEbecause we’ve..

Less codeExtensibleTestable

Monday, September 9, 13

Page 14: Dependency Injection @ AngularJS

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

Page 15: Dependency Injection @ AngularJS

Don’t worry!

Monday, September 9, 13

Page 16: Dependency Injection @ AngularJS

DI Container To The Rescue

Monday, September 9, 13

Page 17: Dependency Injection @ AngularJS

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

Page 18: Dependency Injection @ AngularJS

AngularJS DI

Monday, September 9, 13

Page 19: Dependency Injection @ AngularJS

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

Page 20: Dependency Injection @ AngularJS

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

Page 21: Dependency Injection @ AngularJS

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

Page 22: Dependency Injection @ AngularJS

How Do I Use It?

Monday, September 9, 13

Page 23: Dependency Injection @ AngularJS

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

Page 24: Dependency Injection @ AngularJS

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

Page 25: Dependency Injection @ AngularJS

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

Page 26: Dependency Injection @ AngularJS

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

Page 27: Dependency Injection @ AngularJS

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

Page 28: Dependency Injection @ AngularJS

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

Page 29: Dependency Injection @ AngularJS

Value

Value is a shorthand to register a simple value as a service.

angular.module('myModule') .value('myHttp', 'some string');

Monday, September 9, 13

Page 30: Dependency Injection @ AngularJS

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

Page 31: Dependency Injection @ AngularJS

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

Page 32: Dependency Injection @ AngularJS

Questions?Thank you!

Monday, September 9, 13


Top Related