ngMess: AngularJS Dependency Injection

Post on 02-Jul-2015

245 views 1 download

description

TechTalk on iTechart Hackathon'2014 "ngMess: AngularJS Dependency Injection" - getting a little bit deeper into working with angular services, discussing difference between providers/factories/services/values/constants and reviewing its' source codes. Plus some general advice and use cases for using each type of injectable objects.

Transcript of ngMess: AngularJS Dependency Injection

ngMess: Angular JS DI

Presenter

Dmitry Ivashutin Software Engineer

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.

DI in a Nutshell

create the dependency

look up the dependency

have the dependency injected

The provider

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

How do we usually inject?

http://jsfiddle.net/ae87/9x7Aq/2/

myApp.service('alerter', function () {

this.sayHello = function(){

alert('Hello! ');

}

this.sayGoodbye = function(){

alert('Goodbye!');

} });

Let’s start from

Create provider at configure stage

app.config(function ($provide) {

$provide.provider('greeting', function () {

this.$get = function () {

return function (name) {

alert('Hello, ' + name);

};

};

});

});

It’s a valid way

There are other ways

So called “services”

Factory Service

Value Constant

Provider

Calling exact the same code inside that we wrote above

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_; }

Factory way

function factory(name, factoryFn) { return provider( name,

{ $get: factoryFn }); }

Service way

function service(name, constructor) {

return factory( name, [

'$injector', function ($injector) {

return $injector.instantiate(constructor); } ]); }

Value way

function value(name, val) {

return factory( name,

valueFn(val) ); } function valueFn(value) { return function () { return value; }; }

Constant way

function constant(name, value) { assertNotHasOwnProperty(name, 'constant');

providerCache[name] = value; instanceCache[name] = value; }

Syntactic sugar

Looks annoying, right?

app.config(function($provide) { ... })

Module level access

angular .module('myModule', [])

.provider('greeting', ...);

$provide

.provider('greeting', ...);

“A Sound of Thunder”

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

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

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

Value Recipe

Exposing static values and constants

value(obj)

– registers a value/object that

can only be accessed by

services, not providers

Constant Recipe

Exposing compile time static values and constants

constant(obj)

– registers a value/object

that can be accessed by

providers and services

Decorator

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 }); }; }

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

Few more quick facts

Injector: Why

Feel the power of DI

Control the injection real-time

Access DI container from outside of your app

Primary usage - testing

Injector: How

function MyController($scope, $injector) { $scope.doSomething = function(someServiceName) { // someService contains the name of a service

var service = $injector.get(someServiceName); service.do(); }; }

Scripts require proper order

The End! Questions?