dependency injection @ angularjs

Post on 10-May-2015

2.411 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

Ran Mizrahi from CodeOasis gave a lecture about Angular.js dependency injections, as part of an advanced Angular meetup of the Javascript Israel meetup group. Ran covered how Dependency Injection works in Angular and its internals, what are providers and the different helper methods angular have for defining injectables components.

TRANSCRIPT

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

top related