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

Angular Tips and Tricks

Angular Tips and Tricks

Most of JS developers have seen at least several times the AngularJs into presentations. So most of the people are pretty familiar with AngularJs at this post. This will be two parts presentation. First part will be deep dive into Angular’s injector object, explaining how dependency injection is working. In the second part, I’ll share tips and tricks I learn by working with AngularJs for more than an year.

Code samples can be found at:
https://github.com/RStankov/talk-angular-tips-tricks

Radoslav Stankov

August 27, 2014
Tweet

More Decks by Radoslav Stankov

Other Decks in Technology

Transcript

  1. Radoslav Stankov 27/08/2014

    View full-size slide

  2. Radoslav Stankov
    @rstankov

    !
    !
    !
    !
    http://rstankov.com

    View full-size slide

  3. https://speakerdeck.com/rstankov/angular-tips-and-tricks

    View full-size slide

  4. credits: http://www.bennadel.com/

    View full-size slide

  5. Dependency Injection

    View full-size slide

  6. app = angular.module('Demo', []);

    View full-size slide

  7. app = angular.module('Demo', []);

    View full-size slide

  8. app = angular.module('Demo', []);

    View full-size slide

  9. app.value('Porduct', {
    title: 'iPhone',
    price: 700
    });

    View full-size slide

  10. app.value('Porduct', {
    title: 'iPhone',
    price: 700
    });

    View full-size slide

  11. app.value('Porduct', {
    title: 'iPhone',
    price: 700
    });

    View full-size slide

  12. app.value('Porduct', {
    title: 'iPhone',
    price: 700
    });

    View full-size slide

  13. app.value('Porduct', {
    title: 'iPhone',
    price: 700
    });

    View full-size slide

  14. app.controller(function($scope, Product){
    $scope.product = Product;
    });

    View full-size slide

  15. app.controller(function($scope, Product){
    $scope.product = Product;
    });

    View full-size slide

  16. app.controller(function($scope, Product){
    $scope.product = Product;
    });

    View full-size slide

  17. app.controller(function($scope, Product){
    $scope.product = Product;
    });

    View full-size slide

  18. app.controller(function($scope, Product){
    $scope.product = Product;
    });

    View full-size slide

  19. app.controller(function($scope, Product){
    $scope.product = Product;
    });

    View full-size slide

  20. app.controller(function($scope, Product){
    $scope.product = Product;
    });

    View full-size slide

  21. app.controller(function($scope, Product){
    $scope.product = Product;
    });

    View full-size slide

  22. app.controller(function($scope, Product){
    $scope.product = Product;
    });

    View full-size slide

  23. Error: [$injector:unpr] 

    Unknown provider: ProductProvider <- Product

    View full-size slide

  24. app.value('Porduct', {
    title: 'iPhone',
    price: 700
    });

    View full-size slide

  25. app.value('Porduct', {
    title: 'iPhone',
    price: 700
    });

    View full-size slide

  26. app.value('Porduct', {
    title: 'iPhone',
    price: 700
    });

    View full-size slide

  27. app.value('Product', {
    title: 'iPhone',
    price: 700
    });

    View full-size slide

  28. Error: [$injector:unpr] 

    Unknown provider: ProductProvider <- Product

    View full-size slide

  29. Error: [$injector:unpr] 

    Unknown provider: ProductProvider <- Product

    View full-size slide

  30. Error: [$injector:unpr] 

    Unknown provider: ProductProvider <- Product

    View full-size slide

  31. Error: [$injector:unpr] 

    Unknown provider: ProductProvider <- Product

    View full-size slide

  32. Error: [$injector:unpr] 

    Unknown provider: ProductProvider <- Product

    View full-size slide

  33. Error: [$injector:unpr] 

    Unknown provider: ProductProvider <- Product

    View full-size slide

  34. Error: [$injector:unpr] 

    Unknown provider: ProductProvider <- Product

    View full-size slide

  35. value service factory provider
    injector.get(‘Person’)
    Person

    View full-size slide

  36. app.value('Person', {
    name: 'Rado',
    });

    View full-size slide

  37. app.value('Person', {
    name: 'Rado',
    });

    View full-size slide

  38. app.value('Person', {
    name: 'Rado',
    });

    View full-size slide

  39. app.value('Person', {
    name: 'Rado',
    });

    View full-size slide

  40. app.value('Person', {
    name: 'Rado',
    });

    View full-size slide

  41. app.controller(function($scope, Person, $window) {
    $window.alert(Person.name + ' - hi');
    });

    View full-size slide

  42. app.controller(function($scope, Person, $window) {
    $window.alert(Person.name + ' - hi');
    });

    View full-size slide

  43. app.controller(function($scope, Person, $window) {
    $window.alert(Person.name + ' - hi');
    });

    View full-size slide

  44. app.controller(function($scope, Person, $window) {
    $window.alert(Person.name + ' - hi');
    });

    View full-size slide

  45. app.controller(function($scope, Person, $window) {
    $window.alert(Person.name + ' - hi');
    });

    View full-size slide

  46. injector.get(‘Person’)
    Person

    View full-size slide

  47. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  48. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  49. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  50. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  51. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  52. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  53. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  54. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  55. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  56. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  57. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  58. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  59. app.factory('Person', function($window) {
    var name = '';
    !
    return {
    setName: function(newName) {
    name = newName;
    },
    getName: function() {
    return name;
    },
    say: function(text) {
    $window.alert(name + ' - ' + text);
    }
    }
    });

    View full-size slide

  60. app.controller(function($scope, Person) {
    Person.setName('Radoslav Stankov');
    Person.say('Hi');
    });

    View full-size slide

  61. app.controller(function($scope, Person) {
    Person.setName('Radoslav Stankov');
    Person.say('Hi');
    });

    View full-size slide

  62. app.controller(function($scope, Person) {
    Person.setName('Radoslav Stankov');
    Person.say('Hi');
    });

    View full-size slide

  63. app.controller(function($scope, Person) {
    Person.setName('Radoslav Stankov');
    Person.say('Hi');
    });

    View full-size slide

  64. app.controller(function($scope, Person) {
    Person.setName('Radoslav Stankov');
    Person.say('Hi');
    });

    View full-size slide

  65. Cache? Cache = factory(…)
    false
    true
    injector.get(‘Person’)
    Person

    View full-size slide

  66. app.service('Person', function($window) {
    var name = '';
    !
    this.setName = function(newName) {
    name = newName;
    };
    !
    this.getName = function() {
    return name;
    };
    !
    this.say = function(text) {
    $window.alert(name + ' - ' + text);
    };
    });

    View full-size slide

  67. app.service('Person', function($window) {
    var name = '';
    !
    this.setName = function(newName) {
    name = newName;
    };
    !
    this.getName = function() {
    return name;
    };
    !
    this.say = function(text) {
    $window.alert(name + ' - ' + text);
    };
    });

    View full-size slide

  68. app.service('Person', function($window) {
    var name = '';
    !
    this.setName = function(newName) {
    name = newName;
    };
    !
    this.getName = function() {
    return name;
    };
    !
    this.say = function(text) {
    $window.alert(name + ' - ' + text);
    };
    });

    View full-size slide

  69. app.service('Person', function($window) {
    var name = '';
    !
    this.setName = function(newName) {
    name = newName;
    };
    !
    this.getName = function() {
    return name;
    };
    !
    this.say = function(text) {
    $window.alert(name + ' - ' + text);
    };
    });

    View full-size slide

  70. app.service('Person', function($window) {
    var name = '';
    !
    this.setName = function(newName) {
    name = newName;
    };
    !
    this.getName = function() {
    return name;
    };
    !
    this.say = function(text) {
    $window.alert(name + ' - ' + text);
    };
    });

    View full-size slide

  71. app.controller(function($scope, Person) {
    Person.setName('Radoslav Stankov');
    Person.say('Hi');
    });

    View full-size slide

  72. Cache? Cache = new service(…)
    false
    true
    injector.get(‘Person’)
    Person

    View full-size slide

  73. app.provider('Person', function() {
    this.name = '';
    !
    this.$get = function($window) {
    var self = this;
    return {
    setName: function(newName) {
    self.name = newName;
    },
    getName: function() {
    return self.name;
    },
    say: function(text) {
    $window.alert(self.name + ' - ' + text);
    }
    };
    }
    });

    View full-size slide

  74. app.provider('Person', function() {
    this.name = '';
    !
    this.$get = function($window) {
    var self = this;
    return {
    setName: function(newName) {
    self.name = newName;
    },
    getName: function() {
    return self.name;
    },
    say: function(text) {
    $window.alert(self.name + ' - ' + text);
    }
    };
    }
    });

    View full-size slide

  75. app.provider('Person', function() {
    this.name = '';
    !
    this.$get = function($window) {
    var self = this;
    return {
    setName: function(newName) {
    self.name = newName;
    },
    getName: function() {
    return self.name;
    },
    say: function(text) {
    $window.alert(self.name + ' - ' + text);
    }
    };
    }
    });

    View full-size slide

  76. app.provider('Person', function() {
    this.name = '';
    !
    this.$get = function($window) {
    var self = this;
    return {
    setName: function(newName) {
    self.name = newName;
    },
    getName: function() {
    return self.name;
    },
    say: function(text) {
    $window.alert(self.name + ' - ' + text);
    }
    };
    }
    });

    View full-size slide

  77. app.provider('Person', function() {
    this.name = '';
    !
    this.$get = function($window) {
    var self = this;
    return {
    setName: function(newName) {
    self.name = newName;
    },
    getName: function() {
    return self.name;
    },
    say: function(text) {
    $window.alert(self.name + ' - ' + text);
    }
    };
    }
    });

    View full-size slide

  78. app.provider('Person', function() {
    this.name = '';
    !
    this.$get = function($window) {
    var self = this;
    return {
    setName: function(newName) {
    self.name = newName;
    },
    getName: function() {
    return self.name;
    },
    say: function(text) {
    $window.alert(self.name + ' - ' + text);
    }
    };
    }
    });

    View full-size slide

  79. app.provider('Person', function() {
    this.name = '';
    !
    this.$get = function($window) {
    var self = this;
    return {
    setName: function(newName) {
    self.name = newName;
    },
    getName: function() {
    return self.name;
    },
    say: function(text) {
    $window.alert(self.name + ' - ' + text);
    }
    };
    }
    });

    View full-size slide

  80. app.provider('Person', function() {
    this.name = '';
    !
    this.$get = function($window) {
    var self = this;
    return {
    setName: function(newName) {
    self.name = newName;
    },
    getName: function() {
    return self.name;
    },
    say: function(text) {
    $window.alert(self.name + ' - ' + text);
    }
    };
    }
    });

    View full-size slide

  81. app.provider('Person', function() {
    this.name = '';
    !
    this.$get = function($window) {
    var self = this;
    return {
    setName: function(newName) {
    self.name = newName;
    },
    getName: function() {
    return self.name;
    },
    say: function(text) {
    $window.alert(self.name + ' - ' + text);
    }
    };
    }
    });

    View full-size slide

  82. app.provider('Person', function() {
    this.name = '';
    !
    this.$get = function($window) {
    var self = this;
    return {
    setName: function(newName) {
    self.name = newName;
    },
    getName: function() {
    return self.name;
    },
    say: function(text) {
    $window.alert(self.name + ' - ' + text);
    }
    };
    }
    });

    View full-size slide

  83. app.config(function(PersonProvider){
    PersonProvider.name = 'Rado';
    });

    View full-size slide

  84. app.config(function(PersonProvider){
    PersonProvider.name = 'Rado';
    });

    View full-size slide

  85. app.config(function(PersonProvider){
    PersonProvider.name = 'Rado';
    });

    View full-size slide

  86. app.config(function(PersonProvider){
    PersonProvider.name = 'Rado';
    });

    View full-size slide

  87. app.config(function(PersonProvider){
    PersonProvider.name = 'Rado';
    });

    View full-size slide

  88. app.config(function(PersonProvider){
    PersonProvider.name = 'Rado';
    });

    View full-size slide

  89. app.config(function(PersonProvider){
    PersonProvider.name = 'Rado';
    });

    View full-size slide

  90. app.controller(function($scope, Person) {
    Person.say('Hi');
    });

    View full-size slide

  91. app.controller(function($scope, Person) {
    Person.say('Hi');
    });

    View full-size slide

  92. app.controller(function($scope, Person) {
    Person.say('Hi');
    });

    View full-size slide

  93. Cache? Cache = new provider(…)
    false
    true
    injector.get(‘PersonProvider’)
    PersonProvider

    View full-size slide

  94. Cache?
    false
    true
    injector.get(‘Person’)
    Person
    injector.get(‘PersonProvider’)
    Cache = PersonProvider.$get(…)

    View full-size slide

  95. Error: [$injector:unpr] 

    Unknown provider: ProductProvider <- Product

    View full-size slide

  96. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function value(name, val) {
    return factory(name, valueFn(val));
    }

    View full-size slide

  97. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function value(name, val) {
    return factory(name, valueFn(val));
    }

    View full-size slide

  98. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function value(name, val) {
    return factory(name, valueFn(val));
    }

    View full-size slide

  99. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function value(name, val) {
    return factory(name, valueFn(val));
    }

    View full-size slide

  100. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function value(name, val) {
    return factory(name, valueFn(val));
    }

    View full-size slide

  101. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function value(name, val) {
    return factory(name, valueFn(val));
    }

    View full-size slide

  102. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function value(name, val) {
    return factory(name, valueFn(val));
    }

    View full-size slide

  103. function factory(name, factoryFn) {
    return provider(name, {$get: factoryFn});
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  104. function factory(name, factoryFn) {
    return provider(name, {$get: factoryFn});
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  105. function factory(name, factoryFn) {
    return provider(name, {$get: factoryFn});
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  106. function factory(name, factoryFn) {
    return provider(name, {$get: factoryFn});
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  107. function factory(name, factoryFn) {
    return provider(name, {$get: factoryFn});
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  108. function factory(name, factoryFn) {
    return provider(name, {$get: factoryFn});
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  109. function factory(name, factoryFn) {
    return provider(name, {$get: factoryFn});
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  110. Error: [$injector:unpr] 

    Unknown provider: ProductProvider <- Product

    View full-size slide

  111. Cache?
    false
    true
    injector.get(‘Person’)
    Person
    injector.get(‘PersonProvider’)
    Cache = PersonProvider.$get(…)

    View full-size slide

  112. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  113. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  114. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  115. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  116. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  117. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  118. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  119. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  120. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  121. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  122. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  123. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  124. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  125. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
    return $injector.instantiate(constructor);
    }]);
    }

    View full-size slide

  126. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
    return $injector.instantiate(constructor);
    }]);
    }

    View full-size slide

  127. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
    return $injector.instantiate(constructor);
    }]);
    }

    View full-size slide

  128. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
    return $injector.instantiate(constructor);
    }]);
    }

    View full-size slide

  129. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
    return $injector.instantiate(constructor);
    }]);
    }

    View full-size slide

  130. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
    return $injector.instantiate(constructor);
    }]);
    }

    View full-size slide

  131. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
    return $injector.instantiate(constructor);
    }]);
    }

    View full-size slide

  132. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  133. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  134. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    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 fac
    }
    !
    return providerCache[name + providerSuffix] = provider_;
    }

    View full-size slide

  135. function instantiate(Type, locals, serviceName) {
    var Constructor = function() {};
    Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Typ
    var instance = new Constructor();
    var returnedValue = invoke(Type, instance, locals, serviceName);
    !
    if (isObject(returnedValue) || isFunction(returnedValue)) {
    return returnedValue;
    } else {
    return instance;
    }
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  136. function instantiate(Type, locals, serviceName) {
    var Constructor = function() {};
    Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Typ
    var instance = new Constructor();
    var returnedValue = invoke(Type, instance, locals, serviceName);
    !
    if (isObject(returnedValue) || isFunction(returnedValue)) {
    return returnedValue;
    } else {
    return instance;
    }
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  137. function instantiate(Type, locals, serviceName) {
    var Constructor = function() {};
    Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Typ
    var instance = new Constructor();
    var returnedValue = invoke(Type, instance, locals, serviceName);
    !
    if (isObject(returnedValue) || isFunction(returnedValue)) {
    return returnedValue;
    } else {
    return instance;
    }
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  138. function instantiate(Type, locals, serviceName) {
    var Constructor = function() {};
    Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Typ
    var instance = new Constructor();
    var returnedValue = invoke(Type, instance, locals, serviceName);
    !
    if (isObject(returnedValue) || isFunction(returnedValue)) {
    return returnedValue;
    } else {
    return instance;
    }
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  139. function instantiate(Type, locals, serviceName) {
    var Constructor = function() {};
    Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Typ
    var instance = new Constructor();
    var returnedValue = invoke(Type, instance, locals, serviceName);
    !
    if (isObject(returnedValue) || isFunction(returnedValue)) {
    return returnedValue;
    } else {
    return instance;
    }
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  140. function instantiate(Type, locals, serviceName) {
    var Constructor = function() {};
    Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Typ
    var instance = new Constructor();
    var returnedValue = invoke(Type, instance, locals, serviceName);
    !
    if (isObject(returnedValue) || isFunction(returnedValue)) {
    return returnedValue;
    } else {
    return instance;
    }
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  141. function instantiate(Type, locals, serviceName) {
    var Constructor = function() {};
    Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Typ
    var instance = new Constructor();
    var returnedValue = invoke(Type, instance, locals, serviceName);
    !
    if (isObject(returnedValue) || isFunction(returnedValue)) {
    return returnedValue;
    } else {
    return instance;
    }
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js

    View full-size slide

  142. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  143. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  144. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  145. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  146. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  147. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  148. app.factory('MyFactory', function(Dependancy1, Dependancy2) {
    /* code */
    });

    View full-size slide

  149. app.factory('MyFactory', ['Dependancy1', 'Dependancy2',
    function(Dependancy1, Dependancy2) {
    /* code */
    }
    ]);

    View full-size slide

  150. function MyFactory(Dependancy1, Dependancy2) {
    /* code */
    }
    !
    MyFactory.$inject = ['Dependancy1', 'Dependancy2']
    !
    app.factory('MyFactory', MyFactory);

    View full-size slide

  151. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  152. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  153. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  154. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  155. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  156. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  157. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  158. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  159. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  160. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  161. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  162. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  163. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  164. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  165. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  166. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  167. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  168. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  169. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  170. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  171. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  172. function annotate(fn, strictDi, name) {
    var $inject;
    !
    if (typeof fn === 'function') {
    if (!($inject = fn.$inject)) {
    // ... fill inject from argument names
    }
    } else if (isArray(fn)) {
    var last = fn.length - 1;
    assertArgFn(fn[last], 'fn');
    $inject = fn.slice(0, last);
    } else {
    assertArgFn(fn, 'fn', true);
    }
    return $inject;
    }
    https://github.com/angular/angular.js/blob/master/src/auto/injector.js*

    View full-size slide

  173. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  174. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  175. https://github.com/angular/angular.js/blob/master/src/auto/injector.js*
    function invoke(fn, self, locals, serviceName) {
    var args = [],
    $inject = annotate(fn, strictDi, serviceName);
    !
    for(var i = 0, length = $inject.length; i < length; i++) {
    var key = $inject[i];
    if (typeof key !== 'string') {
    throw $injectorMinErr('...');
    }
    args.push(getService(key));
    }
    !
    return fn.apply(self, args);
    }

    View full-size slide

  176. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    // ... code
    } else {
    // ... code
    }
    }

    View full-size slide

  177. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    if (cache[serviceName] === INSTANTIATING) {
    throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
    serviceName + ' <- ' + path.join(' <- '));
    }
    return cache[serviceName];
    } else {
    // ... code
    }
    }

    View full-size slide

  178. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    if (cache[serviceName] === INSTANTIATING) {
    throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
    serviceName + ' <- ' + path.join(' <- '));
    }
    return cache[serviceName];
    } else {
    // ... code
    }
    }

    View full-size slide

  179. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    if (cache[serviceName] === INSTANTIATING) {
    throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
    serviceName + ' <- ' + path.join(' <- '));
    }
    return cache[serviceName];
    } else {
    // ... code
    }
    }

    View full-size slide

  180. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    if (cache[serviceName] === INSTANTIATING) {
    throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
    serviceName + ' <- ' + path.join(' <- '));
    }
    return cache[serviceName];
    } else {
    // ... code
    }
    }

    View full-size slide

  181. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    if (cache[serviceName] === INSTANTIATING) {
    throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
    serviceName + ' <- ' + path.join(' <- '));
    }
    return cache[serviceName];
    } else {
    // ... code
    }
    }

    View full-size slide

  182. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    if (cache[serviceName] === INSTANTIATING) {
    throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
    serviceName + ' <- ' + path.join(' <- '));
    }
    return cache[serviceName];
    } else {
    // ... code
    }
    }

    View full-size slide

  183. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    if (cache[serviceName] === INSTANTIATING) {
    throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
    serviceName + ' <- ' + path.join(' <- '));
    }
    return cache[serviceName];
    } else {
    // ... code
    }
    }

    View full-size slide

  184. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    // ... code
    } else {
    try {
    path.unshift(serviceName);
    cache[serviceName] = INSTANTIATING;
    return cache[serviceName] = factory(serviceName);
    } catch (err) {
    if (cache[serviceName] === INSTANTIATING) {
    delete cache[serviceName];
    }
    throw err;
    } finally {
    path.shift();
    }
    }
    }

    View full-size slide

  185. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    // ... code
    } else {
    try {
    path.unshift(serviceName);
    cache[serviceName] = INSTANTIATING;
    return cache[serviceName] = factory(serviceName);
    } catch (err) {
    if (cache[serviceName] === INSTANTIATING) {
    delete cache[serviceName];
    }
    throw err;
    } finally {
    path.shift();
    }
    }
    }

    View full-size slide

  186. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    // ... code
    } else {
    try {
    path.unshift(serviceName);
    cache[serviceName] = INSTANTIATING;
    return cache[serviceName] = factory(serviceName);
    } catch (err) {
    if (cache[serviceName] === INSTANTIATING) {
    delete cache[serviceName];
    }
    throw err;
    } finally {
    path.shift();
    }
    }
    }

    View full-size slide

  187. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    // ... code
    } else {
    try {
    path.unshift(serviceName);
    cache[serviceName] = INSTANTIATING;
    return cache[serviceName] = factory(serviceName);
    } catch (err) {
    if (cache[serviceName] === INSTANTIATING) {
    delete cache[serviceName];
    }
    throw err;
    } finally {
    path.shift();
    }
    }
    }

    View full-size slide

  188. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    // ... code
    } else {
    try {
    path.unshift(serviceName);
    cache[serviceName] = INSTANTIATING;
    return cache[serviceName] = factory(serviceName);
    } catch (err) {
    if (cache[serviceName] === INSTANTIATING) {
    delete cache[serviceName];
    }
    throw err;
    } finally {
    path.shift();
    }
    }
    }

    View full-size slide

  189. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    // ... code
    } else {
    try {
    path.unshift(serviceName);
    cache[serviceName] = INSTANTIATING;
    return cache[serviceName] = factory(serviceName);
    } catch (err) {
    if (cache[serviceName] === INSTANTIATING) {
    delete cache[serviceName];
    }
    throw err;
    } finally {
    path.shift();
    }
    }
    }

    View full-size slide

  190. https://github.com/angular/angular.js/blob/master/src/auto/injector.js
    function getService(serviceName) {
    if (cache.hasOwnProperty(serviceName)) {
    // ... code
    } else {
    try {
    path.unshift(serviceName);
    cache[serviceName] = INSTANTIATING;
    return cache[serviceName] = factory(serviceName);
    } catch (err) {
    if (cache[serviceName] === INSTANTIATING) {
    delete cache[serviceName];
    }
    throw err;
    } finally {
    path.shift();
    }
    }
    }

    View full-size slide

  191. Error: [$injector:unpr] 

    Unknown provider: ProductProvider <- Product

    View full-size slide

  192. angular.injector(['Demo']).invoke(function(Product) {
    /* code */
    });

    View full-size slide

  193. Uncaught Error: [$injector:unpr] Unknown provider:
    !
    $rootElementProvider <- $rootElement <- $location <- $http <- $resource
    <- Product

    View full-size slide

  194. Uncaught Error: [$injector:unpr] Unknown provider:
    !
    $rootElementProvider <- $rootElement <- $location <- $http <- $resource
    <- Product

    View full-size slide

  195. Uncaught Error: [$injector:unpr] Unknown provider:
    !
    $rootElementProvider <- $rootElement <- $location <- $http <- $resource
    <- Product

    View full-size slide

  196. https://docs.angularjs.org/guide/bootstrap

    View full-size slide

  197. https://github.com/angular/angular.js/blob/master/src/Angular.js
    function bootstrap(element, modules, config) {
    // ... setup
    !
    var doBootstrap = function() {
    // ... do bootstrapping
    };
    !
    // ... call doBootstrap
    }

    View full-size slide

  198. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  199. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  200. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  201. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  202. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  203. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  204. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  205. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  206. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  207. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  208. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  209. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  210. https://github.com/angular/angular.js/blob/master/src/Angular.js
    var doBootstrap = function() {
    element = jqLite(element);
    !
    // ...
    !
    modules.unshift(['$provide', function($provide) {
    $provide.value('$rootElement', 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;
    };

    View full-size slide

  211. angular.element(
    document.querySelector(‘[ng-app]’)
    ).data(‘injector').invoke(function(Product){
    /* code */
    });

    View full-size slide

  212. angular.element(
    document.querySelector(‘[ng-app]’)
    ).injector().invoke(function(Product){
    /* code */
    });

    View full-size slide

  213. // development.js
    app.invoke = function(fn) {
    var dom = document.querySelector('[ng-app="' + this.name + '"]'),
    element = angular.element(dom);
    !
    return element.injector().invoke(fn);
    }
    1

    View full-size slide

  214. !
    app.invoke(function(Product) {
    /* code */
    });

    View full-size slide

  215. Angular 2.0 (ES6+)

    View full-size slide

  216. Tips and Tricks

    View full-size slide

  217. uiRouter
    https://github.com/angular-ui/ui-router
    2

    View full-size slide

  218. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  219. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  220. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  221. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  222. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  223. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  224. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  225. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  226. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  227. Nested routes
    https://github.com/angular-ui/ui-router/wiki/Nested-States-&-Nested-Views
    /settings/
    /settings/passwords
    /settings/invoices/
    /settings/invoices/:id
    /settings/repos/
    /settings/repos/new

    /settings/repos/:id

    View full-size slide

  228. Multiple named views
    https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views

    View full-size slide

  229. Multiple named views
    https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views

    View full-size slide

  230. Multiple named views
    https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views

    View full-size slide

  231. Multiple named views
    https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views

    View full-size slide

  232. ui-sref
    https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref
    Home |
    About
    !



    {{contact.name}}



    View full-size slide

  233. ui-sref
    https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref
    Home |
    About
    !



    {{contact.name}}



    View full-size slide

  234. ui-sref
    https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref
    Home |
    About
    !



    {{contact.name}}



    View full-size slide

  235. ui-sref
    https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref
    Home |
    About
    !



    {{contact.name}}



    View full-size slide

  236. ui-sref
    https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref
    Home |
    About
    !



    {{contact.name}}



    View full-size slide

  237. Interceptors

    View full-size slide

  238. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  239. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  240. app.config(function($stateProvider) {
    $stateProvider
    .state('product', {
    url: '/product/:id',
    controller: ‘productCtrl',
    templateUrl: ‘product.html',
    resolve: {
    product: function($stateParams, Product) {
    return Product.get(id: $stateParams.id).$promise;
    }
    }
    });
    });

    View full-size slide

  241. app.config(function($httpProvider) {
    var CODE_MAPPING = {
    401: '/errors/unauthorized',
    404: ‘/errors/not_found'
    };
    !
    $httpProvider.interceptors.push(function($q, $location) {
    return {
    'responseError': function(rejection) {
    var path = CODE_MAPPING[rejection.status];
    if (path) {
    return $location.path(path);
    } else {
    return $q.reject(rejection);
    }
    }
    };
    });
    });
    3

    View full-size slide

  242. app.config(function($httpProvider) {
    var CODE_MAPPING = {
    401: '/errors/unauthorized',
    404: ‘/errors/not_found'
    };
    !
    $httpProvider.interceptors.push(function($q, $location) {
    return {
    'responseError': function(rejection) {
    var path = CODE_MAPPING[rejection.status];
    if (path) {
    return $location.path(path);
    } else {
    return $q.reject(rejection);
    }
    }
    };
    });
    });
    3

    View full-size slide

  243. app.config(function($httpProvider) {
    var CODE_MAPPING = {
    401: '/errors/unauthorized',
    404: ‘/errors/not_found'
    };
    !
    $httpProvider.interceptors.push(function($q, $location) {
    return {
    'responseError': function(rejection) {
    var path = CODE_MAPPING[rejection.status];
    if (path) {
    return $location.path(path);
    } else {
    return $q.reject(rejection);
    }
    }
    };
    });
    });
    3

    View full-size slide

  244. app.config(function($httpProvider) {
    var CODE_MAPPING = {
    401: '/errors/unauthorized',
    404: ‘/errors/not_found'
    };
    !
    $httpProvider.interceptors.push(function($q, $location) {
    return {
    'responseError': function(rejection) {
    var path = CODE_MAPPING[rejection.status];
    if (path) {
    return $location.path(path);
    } else {
    return $q.reject(rejection);
    }
    }
    };
    });
    });
    3

    View full-size slide

  245. app.config(function($httpProvider) {
    var CODE_MAPPING = {
    401: '/errors/unauthorized',
    404: ‘/errors/not_found'
    };
    !
    $httpProvider.interceptors.push(function($q, $location) {
    return {
    'responseError': function(rejection) {
    var path = CODE_MAPPING[rejection.status];
    if (path) {
    return $location.path(path);
    } else {
    return $q.reject(rejection);
    }
    }
    };
    });
    });
    3

    View full-size slide

  246. app.config(function($httpProvider) {
    var CODE_MAPPING = {
    401: '/errors/unauthorized',
    404: ‘/errors/not_found'
    };
    !
    $httpProvider.interceptors.push(function($q, $location) {
    return {
    'responseError': function(rejection) {
    var path = CODE_MAPPING[rejection.status];
    if (path) {
    return $location.path(path);
    } else {
    return $q.reject(rejection);
    }
    }
    };
    });
    });
    3

    View full-size slide

  247. app.config(function($httpProvider) {
    var CODE_MAPPING = {
    401: '/errors/unauthorized',
    404: ‘/errors/not_found'
    };
    !
    $httpProvider.interceptors.push(function($q, $location) {
    return {
    'responseError': function(rejection) {
    var path = CODE_MAPPING[rejection.status];
    if (path) {
    return $location.path(path);
    } else {
    return $q.reject(rejection);
    }
    }
    };
    });
    });
    3

    View full-size slide

  248. app.config(function($httpProvider) {
    var CODE_MAPPING = {
    401: '/errors/unauthorized',
    404: ‘/errors/not_found'
    };
    !
    $httpProvider.interceptors.push(function($q, $location) {
    return {
    'responseError': function(rejection) {
    var path = CODE_MAPPING[rejection.status];
    if (path) {
    return $location.path(path);
    } else {
    return $q.reject(rejection);
    }
    }
    };
    });
    });
    3

    View full-size slide

  249. app.config(function($httpProvider) {
    var CODE_MAPPING = {
    401: '/errors/unauthorized',
    404: ‘/errors/not_found'
    };
    !
    $httpProvider.interceptors.push(function($q, $location) {
    return {
    'responseError': function(rejection) {
    var path = CODE_MAPPING[rejection.status];
    if (path) {
    return $location.path(path);
    } else {
    return $q.reject(rejection);
    }
    }
    };
    });
    });
    3

    View full-size slide

  250. app.config(function($httpProvider) {
    var CODE_MAPPING = {
    401: '/errors/unauthorized',
    404: ‘/errors/not_found'
    };
    !
    $httpProvider.interceptors.push(function($q, $location) {
    return {
    'responseError': function(rejection) {
    var path = CODE_MAPPING[rejection.status];
    if (path) {
    return $location.path(path);
    } else {
    return $q.reject(rejection);
    }
    }
    };
    });
    });
    3

    View full-size slide

  251. app.config(function($httpProvider) {
    var CODE_MAPPING = {
    401: '/errors/unauthorized',
    404: ‘/errors/not_found'
    };
    !
    $httpProvider.interceptors.push(function($q, $location) {
    return {
    'responseError': function(rejection) {
    var path = CODE_MAPPING[rejection.status];
    if (path) {
    return $location.path(path);
    } else {
    return $q.reject(rejection);
    }
    }
    };
    });
    });
    3

    View full-size slide

  252. 4
    app.directive('simpleFileUpload', function() {
    return {
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
    return element.on('change', function(event) {
    return scope.$apply(function() {
    return ngModel.$setViewValue(event.target.files[0]);
    });
    });
    }
    };
    });

    View full-size slide

  253. 4
    app.directive('simpleFileUpload', function() {
    return {
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
    return element.on('change', function(event) {
    return scope.$apply(function() {
    return ngModel.$setViewValue(event.target.files[0]);
    });
    });
    }
    };
    });

    View full-size slide

  254. 4
    app.directive('simpleFileUpload', function() {
    return {
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
    return element.on('change', function(event) {
    return scope.$apply(function() {
    return ngModel.$setViewValue(event.target.files[0]);
    });
    });
    }
    };
    });

    View full-size slide

  255. 4
    app.directive('simpleFileUpload', function() {
    return {
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
    return element.on('change', function(event) {
    return scope.$apply(function() {
    return ngModel.$setViewValue(event.target.files[0]);
    });
    });
    }
    };
    });

    View full-size slide

  256. 4
    app.directive('simpleFileUpload', function() {
    return {
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
    return element.on('change', function(event) {
    return scope.$apply(function() {
    return ngModel.$setViewValue(event.target.files[0]);
    });
    });
    }
    };
    });

    View full-size slide

  257. 4
    app.directive('simpleFileUpload', function() {
    return {
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
    return element.on('change', function(event) {
    return scope.$apply(function() {
    return ngModel.$setViewValue(event.target.files[0]);
    });
    });
    }
    };
    });

    View full-size slide

  258. 4
    app.directive('simpleFileUpload', function() {
    return {
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
    return element.on('change', function(event) {
    return scope.$apply(function() {
    return ngModel.$setViewValue(event.target.files[0]);
    });
    });
    }
    };
    });

    View full-size slide

  259. 4
    app.directive('simpleFileUpload', function() {
    return {
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
    return element.on('change', function(event) {
    return scope.$apply(function() {
    return ngModel.$setViewValue(event.target.files[0]);
    });
    });
    }
    };
    });

    View full-size slide

  260. 4
    app.directive('simpleFileUpload', function() {
    return {
    require: '?ngModel',
    link: function(scope, element, attrs, ngModel) {
    return element.on('change', function(event) {
    return scope.$apply(function() {
    return ngModel.$setViewValue(event.target.files[0]);
    });
    });
    }
    };
    });

    View full-size slide

  261. transclusion

    View full-size slide


  262. Long text
    Very long text
    Very very long text
    Even longer text than the very very long text

    View full-size slide


  263. Long text
    Very long text
    Very very long text
    Even longer text than the very very long text

    View full-size slide


  264. Long text
    Very long text
    Very very long text
    Even longer text than the very very long text

    View full-size slide


  265. Long text
    Very long text
    Very very long text
    Even longer text than the very very long text

    View full-size slide


  266. Long text
    Very long text
    Very very long text
    Even longer text than the very very long text

    View full-size slide

  267. !
    !

    Description

    Long text
    Very long text
    Very very long text
    Even longer text than the very very long text


    View full-size slide

  268. !
    !

    Description

    Long text
    Very long text
    Very very long text
    Even longer text than the very very long text


    View full-size slide

  269. !
    !

    Description

    Long text
    Very long text
    Very very long text
    Even longer text than the very very long text


    View full-size slide

  270. 5
    app.directive('myPanel', function() {
    return {
    restrict: 'E',
    transclude: true,
    scope: {
    title: '=title'
    },
    template:
    '' +
    '{{title}}' +
    '' +
    ''
    };
    });

    View full-size slide

  271. 5
    app.directive('myPanel', function() {
    return {
    restrict: 'E',
    transclude: true,
    scope: {
    title: '=title'
    },
    template:
    '' +
    '{{title}}' +
    '' +
    ''
    };
    });

    View full-size slide

  272. 5
    app.directive('myPanel', function() {
    return {
    restrict: 'E',
    transclude: true,
    scope: {
    title: '=title'
    },
    template:
    '' +
    '{{title}}' +
    '' +
    ''
    };
    });

    View full-size slide

  273. 5
    app.directive('myPanel', function() {
    return {
    restrict: 'E',
    transclude: true,
    scope: {
    title: '=title'
    },
    template:
    '' +
    '{{title}}' +
    '' +
    ''
    };
    });

    View full-size slide

  274. 5
    app.directive('myPanel', function() {
    return {
    restrict: 'E',
    transclude: true,
    scope: {
    title: '=title'
    },
    template:
    '' +
    '{{title}}' +
    '' +
    ''
    };
    });

    View full-size slide

  275. 5
    app.directive('myPanel', function() {
    return {
    restrict: 'E',
    transclude: true,
    scope: {
    title: '=title'
    },
    template:
    '' +
    '{{title}}' +
    '' +
    ''
    };
    });

    View full-size slide

  276. 5
    app.directive('myPanel', function() {
    return {
    restrict: 'E',
    transclude: true,
    scope: {
    title: '=title'
    },
    template:
    '' +
    '{{title}}' +
    '' +
    ''
    };
    });

    View full-size slide

  277. 5
    app.directive('myPanel', function() {
    return {
    restrict: 'E',
    transclude: true,
    scope: {
    title: '=title'
    },
    template:
    '' +
    '{{title}}' +
    '' +
    ''
    };
    });

    View full-size slide

  278. 5
    app.directive('myPanel', function() {
    return {
    restrict: 'E',
    transclude: true,
    scope: {
    title: '=title'
    },
    template:
    '' +
    '{{title}}' +
    '' +
    ''
    };
    });

    View full-size slide


  279. Long text
    Very long text
    Very very long text
    Even longer text than the very very long text

    View full-size slide

  280. !
    !

    Description

    Long text
    Very long text
    Very very long text
    Even longer text than the very very long text


    View full-size slide

  281. ng-if vs ng-show/ng-hide
    6

    View full-size slide

  282. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngShowHide.js
    var ngShowDirective = ['$animate', function($animate) {
    return {
    restrict: 'A',
    multiElement: true,
    link: function(scope, element, attr) {
    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
    $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide')
    });
    }
    };
    }];

    View full-size slide

  283. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngShowHide.js
    var ngShowDirective = ['$animate', function($animate) {
    return {
    restrict: 'A',
    multiElement: true,
    link: function(scope, element, attr) {
    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
    $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide')
    });
    }
    };
    }];

    View full-size slide

  284. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngShowHide.js
    var ngShowDirective = ['$animate', function($animate) {
    return {
    restrict: 'A',
    multiElement: true,
    link: function(scope, element, attr) {
    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
    $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide')
    });
    }
    };
    }];

    View full-size slide

  285. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngShowHide.js
    var ngShowDirective = ['$animate', function($animate) {
    return {
    restrict: 'A',
    multiElement: true,
    link: function(scope, element, attr) {
    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
    $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide')
    });
    }
    };
    }];

    View full-size slide

  286. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngShowHide.js
    var ngShowDirective = ['$animate', function($animate) {
    return {
    restrict: 'A',
    multiElement: true,
    link: function(scope, element, attr) {
    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
    $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide')
    });
    }
    };
    }];

    View full-size slide

  287. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngShowHide.js
    var ngShowDirective = ['$animate', function($animate) {
    return {
    restrict: 'A',
    multiElement: true,
    link: function(scope, element, attr) {
    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
    $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide')
    });
    }
    };
    }];

    View full-size slide

  288. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngShowHide.js
    var ngShowDirective = ['$animate', function($animate) {
    return {
    restrict: 'A',
    multiElement: true,
    link: function(scope, element, attr) {
    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
    $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide')
    });
    }
    };
    }];

    View full-size slide

  289. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngShowHide.js
    var ngShowDirective = ['$animate', function($animate) {
    return {
    restrict: 'A',
    multiElement: true,
    link: function(scope, element, attr) {
    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
    $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide')
    });
    }
    };
    }];

    View full-size slide

  290. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngShowHide.js
    var ngShowDirective = ['$animate', function($animate) {
    return {
    restrict: 'A',
    multiElement: true,
    link: function(scope, element, attr) {
    scope.$watch(attr.ngShow, function ngShowWatchAction(value){
    $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide')
    });
    }
    };
    }];

    View full-size slide

  291. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngIf.js
    var ngIfDirective = ['$animate', function($animate) {
    return {
    transclude: 'element',
    // ... settings
    link: function ($scope, $element, $attr, ctrl, $transclude) {
    $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
    if (value) {
    // add content from page
    } else {
    // remove content from page
    }
    });
    }
    };
    }];

    View full-size slide

  292. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngIf.js
    var ngIfDirective = ['$animate', function($animate) {
    return {
    transclude: 'element',
    // ... settings
    link: function ($scope, $element, $attr, ctrl, $transclude) {
    $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
    if (value) {
    // add content from page
    } else {
    // remove content from page
    }
    });
    }
    };
    }];

    View full-size slide

  293. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngIf.js
    var ngIfDirective = ['$animate', function($animate) {
    return {
    transclude: 'element',
    // ... settings
    link: function ($scope, $element, $attr, ctrl, $transclude) {
    $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
    if (value) {
    // add content from page
    } else {
    // remove content from page
    }
    });
    }
    };
    }];

    View full-size slide

  294. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngIf.js
    var ngIfDirective = ['$animate', function($animate) {
    return {
    transclude: 'element',
    // ... settings
    link: function ($scope, $element, $attr, ctrl, $transclude) {
    $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
    if (value) {
    // add content from page
    } else {
    // remove content from page
    }
    });
    }
    };
    }];

    View full-size slide

  295. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngIf.js
    var ngIfDirective = ['$animate', function($animate) {
    return {
    transclude: 'element',
    // ... settings
    link: function ($scope, $element, $attr, ctrl, $transclude) {
    $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
    if (value) {
    // add content from page
    } else {
    // remove content from page
    }
    });
    }
    };
    }];

    View full-size slide

  296. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngIf.js
    var ngIfDirective = ['$animate', function($animate) {
    return {
    transclude: 'element',
    // ... settings
    link: function ($scope, $element, $attr, ctrl, $transclude) {
    $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
    if (value) {
    // add content from page
    } else {
    // remove content from page
    }
    });
    }
    };
    }];

    View full-size slide

  297. https://github.com/angular/angular.js/blob/master/src/ng/directive/ngIf.js
    var ngIfDirective = ['$animate', function($animate) {
    return {
    transclude: 'element',
    // ... settings
    link: function ($scope, $element, $attr, ctrl, $transclude) {
    $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
    if (value) {
    // add content from page
    } else {
    // remove content from page
    }
    });
    }
    };
    }];

    View full-size slide

  298. https://github.com/Pasvaz/bindonce
    7

    View full-size slide


  299. !

    {{::item.name}}

    https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

    View full-size slide


  300. !

    {{::item.name}}

    https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

    View full-size slide


  301. !

    {{::item.name}}

    https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

    View full-size slide


  302. !

    {{::item.name}}

    https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

    View full-size slide


  303. !

    {{::item.name}}

    https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

    View full-size slide


  304. !

    {{::item.name}}

    https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

    View full-size slide


  305. !

    {{::item.name}}

    https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

    View full-size slide

  306. https://github.com/RStankov/talk-angular-tips-tricks
    The code commit by commit

    View full-size slide

  307. И сега на къде?
    https://angularjs.org/

    View full-size slide

  308. @rstankov
    Thank you :)

    View full-size slide