Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to AngularJS Dependency Injection

Introduction to AngularJS Dependency Injection

Avatar for Borys Semerenko

Borys Semerenko

November 13, 2014
Tweet

More Decks by Borys Semerenko

Other Decks in Programming

Transcript

  1. Dependency injection is a software design pattern that implements inversion

    of control and allows a program design to follow the dependency inversion principle.
  2. There are only three ways a component (object or function)

    can get a hold of its dependencies: function User( name ) { this.name = name; this.storage = new Storage(); this.service = new UserService(); } ➔ The component can create the dependency, typically using the new operator. ➔ The component can look up the dependency, by referring to a global variable ➔ The component can have the dependency passed to it where it is needed. function User( name ) { this.name = name; this.storage = storage; this.service = userService; } function User( name, storage, service ) { this.name = name; this.storage = storage; this.service = service; }
  3. To manage the responsibility of dependency injection, each Angular application

    has an injector. ➔ Automatic Initialization ➔ Manual Initialization Bootstrap application types:
  4. Automatic Initialization: jqLite(document).ready(function() { angularInit(document, bootstrap); }); function angularInit(element, bootstrap)

    { var appElement, module, config = {}; .... forEach(ngAttrPrefixes, function(prefix) { var name = prefix + 'app'; var candidate; if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) { appElement = candidate; module = candidate.getAttribute(name); } }); if (appElement) { config.strictDi = getNgAttribute(appElement, 'strict-di') !== null; bootstrap(appElement, module ? [module] : [], config); } }
  5. Automatic Initialization: function bootstrap(element, modules, config) { .... var doBootstrap

    = function() { element = jqLite(element); .... modules.unshift('ng'); var injector = createInjector(modules, config.strictDi); injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', function bootstrapApply(scope, element, compile, injector) { scope.$apply(function() { element.data('$injector', injector); compile(element)(scope); }); }] ); return injector; }; .... if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { return doBootstrap(); } .... }
  6. Manual Initialization var applicationModule = angular.module('applicationModule', []); var injector =

    angular.bootstrap( document, ['applicationModule']); or var productsApp = angular.module('productsApp', []); var pollsApp = angular.module('pollsApp ', []); angular.bootstrap( document.getElementById('products'), ['productsApp']); angular.bootstrap( document.getElementById('polls'), ['pollsApp']); or var applicationModule = angular.module('applicationModule', []).value('nowTime', Date.now()); var $injector = angular.injector(['applicationModule']); $injector.invoke(['nowTime', function( nowTime ) { console.log( nowTime ); }]);
  7. function createInjector( .... ) { var providerCache = {}, instanceCache

    = {}; return { invoke: invoke, instantiate: instantiate, get: getService, annotate: annotate, has: function(name) { return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name); } }; } $injector object
  8. Dependency annotation app.controller('ProductListController', ['$log', '$scope', function( $log, $scope ) {

    .... }]); ➔ Inline Array Annotation ➔ $inject Property Annotation ➔ Implicit Annotation var ProductListController = function() { .... }; ProductListController.$inject = ['$log', '$scope']; app.controller('ProductListController', ProductListController); app.controller('ProductListController', function( $log, $scope ) { .... });
  9. Implicit annotation app.controller('ProductListController', function( $log, $scope ) { .... });

    (function( $log, $scope ) { .... }).length; 2 (function( $log, $scope ) { .... }).toString(); 'function( $log, $scope ) { .... }' fnString.match(/^function\s*[^\(]*\(\s*([^\)]*)\)/m) ["function( $log, $scope )", "$log, $scope"]
  10. Providers $httpProvider $http $rootScopeProvide r $rootScope Available in config phase!!!

    angular.module('app', []).config(['$provide', function( $provide ) { $provide.provider('currencySign', function() { .... }); }]); angular.module('app', []).provider('currencySign', function() { .... });
  11. function provider(name, provider_) { assertNotHasOwnProperty(name, 'service'); if (isFunction(provider_) || isArray(provider_))

    { provider_ = providerInjector.instantiate(provider_); } if (!provider_.$get) { throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name); } return providerCache[name + providerSuffix] = provider_; } Providers angular.module('app', []).config(['$provide', function( $provide ) { $provide.provider('currencySign', function() { var symbol = '$'; this.setSymbol = function( newSymbol ) { symbol = newSymbol; }; this.$get = function() { return { get: function() { return symbol; } }; }; }); }]); example:
  12. Provider syntactic sugar (recipes) function factory(name, factoryFn, enforce) { return

    provider(name, { $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn }); } function service(name, constructor) { return factory(name, ['$injector', function($injector) { return $injector.instantiate(constructor); }]); } function value(name, val) { return factory(name, valueFn(val), false); } function constant(name, value) { assertNotHasOwnProperty(name, 'constant'); providerCache[name] = value; instanceCache[name] = value; } Value, Factory, Service and Constant
  13. Built-in providers ➔ $anchorScrollProvider ➔ $animateProvider ➔ $compileProvider ➔ $controllerProvider

    ➔ $filterProvider ➔ $httpProvider ➔ $interpolateProvider ➔ $locationProvider ➔ $logProvider ➔ $parseProvider ➔ $rootScopeProvider ➔ $sceDelegateProvider ➔ $sceProvider
  14. Service function(servicename) { var provider = providerInjector.get(servicename + providerSuffix); return

    instanceInjector.invoke(provider.$get, provider, undefined, servicename); } Angular services are: ➔ Lazily instantiated ➔ Singletons
  15. function invoke(fn, self, locals, serviceName) { .... var args =

    [], $inject = annotate(fn, strictDi, serviceName); for (i = 0, length = $inject.length; i < length; i++) { key = $inject[i]; args.push( locals && locals.hasOwnProperty(key) ? locals[key] : getService(key) ); } .... return fn.apply(self, args); } function getService(serviceName) { if (cache.hasOwnProperty(serviceName)) { .... return cache[serviceName]; } else { .... return cache[serviceName] = factory(serviceName); .... } } $injector.invoke
  16. Built-in services ➔ $anchorScroll ➔ $animate ➔ $cacheFactory ➔ $compile

    ➔ $controller ➔ $document ➔ $exceptionHandler ➔ $filter ➔ $http ➔ $httpBackend ➔ $interpolate ➔ $interval ➔ $locale ➔ $location ➔ $log ➔ $parse ➔ $q ➔ $rootElement ➔ $rootScope ➔ $sce ➔ $sceDelegate ➔ $templateCache ➔ $templateRequest ➔ $timeout ➔ $window
  17. DI is used in: ➔ module.config() - providers and constants

    ➔ module.provider() - providers and constants ➔ module.run() - services, values and constants ➔ module.controller() - services, values, constants + $scope ➔ module.factory() - services, values and constants ➔ module.service() - services, values and constants ➔ module.directive() - services, values and constants ➔ module.filter() - services, values and constants ➔ module.animation() - services, values and constants ➔ module.decorator() - services, values and constants + $delegate ➔ provider.$get - services, values and constants