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

Introduction to AngularJS Dependency Injection

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →

Introduction to AngularJS Dependency Injection

Avatar for Borys Semerenko

Borys Semerenko

November 13, 2014

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