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

7a0e72a6f55811246bb5d9a946fd2e49?s=128

Radoslav Stankov

August 27, 2014
Tweet

Transcript

  1. Radoslav Stankov 27/08/2014

  2. Radoslav Stankov @rstankov ! ! ! ! http://rstankov.com

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

  5. None
  6. None
  7. None
  8. credits: http://www.bennadel.com/

  9. None
  10. Dependency Injection

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  28. Error: [$injector:unpr] 
 Unknown provider: ProductProvider <- Product

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

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

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

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

  34. Error: [$injector:unpr] 
 Unknown provider: ProductProvider <- Product

  35. Error: [$injector:unpr] 
 Unknown provider: ProductProvider <- Product

  36. Error: [$injector:unpr] 
 Unknown provider: ProductProvider <- Product

  37. Error: [$injector:unpr] 
 Unknown provider: ProductProvider <- Product

  38. Error: [$injector:unpr] 
 Unknown provider: ProductProvider <- Product

  39. Error: [$injector:unpr] 
 Unknown provider: ProductProvider <- Product

  40. Error: [$injector:unpr] 
 Unknown provider: ProductProvider <- Product

  41. None
  42. value service factory provider injector.get(‘Person’) Person

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

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

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

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

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

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

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

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

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

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

  53. injector.get(‘Person’) Person

  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); } } });
  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); } } });
  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); } } });
  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); } } });
  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); } } });
  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); } } });
  60. app.factory('Person', function($window) { var name = ''; ! return {

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

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

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

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

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

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

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  67. app.controller(function($scope, Person) { Person.setName('Radoslav Stankov'); Person.say('Hi'); });

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

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

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

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

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

  73. 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); }; });
  74. 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); }; });
  75. 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); }; });
  76. 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); }; });
  77. 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); }; });
  78. app.controller(function($scope, Person) { Person.setName('Radoslav Stankov'); Person.say('Hi'); });

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

  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); } }; } });
  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); } }; } });
  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); } }; } });
  83. 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); } }; } });
  84. 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); } }; } });
  85. 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); } }; } });
  86. 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); } }; } });
  87. 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); } }; } });
  88. 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); } }; } });
  89. 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); } }; } });
  90. app.config(function(PersonProvider){ PersonProvider.name = 'Rado'; });

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

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

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

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

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

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

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

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

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

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

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

  102. Error: [$injector:unpr] 
 Unknown provider: ProductProvider <- Product

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  119. Error: [$injector:unpr] 
 Unknown provider: ProductProvider <- Product

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

  121. None
  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_; }
  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_; }
  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_; }
  125. 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_; }
  126. 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_; }
  127. 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_; }
  128. 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_; }
  129. 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_; }
  130. 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_; }
  131. 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_; }
  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_; }
  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_; }
  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_; }
  135. 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); }]); }
  136. 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); }]); }
  137. 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); }]); }
  138. 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); }]); }
  139. 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); }]); }
  140. 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); }]); }
  141. 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); }]); }
  142. 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_; }
  143. 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_; }
  144. 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_; }
  145. 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
  146. 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
  147. 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
  148. 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
  149. 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
  150. 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
  151. 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
  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); }
  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); }
  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); }
  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); }
  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); }
  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); }
  158. app.factory('MyFactory', function(Dependancy1, Dependancy2) { /* code */ });

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

    ]);
  160. function MyFactory(Dependancy1, Dependancy2) { /* code */ } ! MyFactory.$inject

    = ['Dependancy1', 'Dependancy2'] ! app.factory('MyFactory', MyFactory);
  161. 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); }
  162. 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); }
  163. 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); }
  164. 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); }
  165. 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); }
  166. 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); }
  167. 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); }
  168. 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); }
  169. 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); }
  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*
  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*
  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*
  173. 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*
  174. 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*
  175. 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*
  176. 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*
  177. 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*
  178. 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*
  179. 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*
  180. 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*
  181. 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*
  182. 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*
  183. 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); }
  184. 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); }
  185. 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); }
  186. https://github.com/angular/angular.js/blob/master/src/auto/injector.js function getService(serviceName) { if (cache.hasOwnProperty(serviceName)) { // ... code

    } else { // ... code } }
  187. 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 } }
  188. 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 } }
  189. 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 } }
  190. 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 } }
  191. 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 } }
  192. 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 } }
  193. 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 } }
  194. 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(); } } }
  195. 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(); } } }
  196. 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(); } } }
  197. 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(); } } }
  198. 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(); } } }
  199. 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(); } } }
  200. 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(); } } }
  201. Error: [$injector:unpr] 
 Unknown provider: ProductProvider <- Product

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

  204. Uncaught Error: [$injector:unpr] Unknown provider: ! $rootElementProvider <- $rootElement <-

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

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

    $location <- $http <- $resource <- Product
  207. None
  208. https://docs.angularjs.org/guide/bootstrap

  209. https://github.com/angular/angular.js/blob/master/src/Angular.js function bootstrap(element, modules, config) { // ... setup !

    var doBootstrap = function() { // ... do bootstrapping }; ! // ... call doBootstrap }
  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; };
  211. 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; };
  212. 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; };
  213. 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; };
  214. 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; };
  215. 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; };
  216. 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; };
  217. 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; };
  218. 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; };
  219. 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; };
  220. 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; };
  221. 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; };
  222. 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; };
  223. angular.element( document.querySelector(‘[ng-app]’) ).data(‘injector').invoke(function(Product){ /* code */ });

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

  225. None
  226. // development.js app.invoke = function(fn) { var dom = document.querySelector('[ng-app="'

    + this.name + '"]'), element = angular.element(dom); ! return element.injector().invoke(fn); } 1
  227. ! app.invoke(function(Product) { /* code */ });

  228. ngMock

  229. Angular 2.0 (ES6+)

  230. None
  231. Tips and Tricks

  232. ngRouter

  233. ngRouter

  234. ngRouter

  235. uiRouter

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

  237. 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; } } }); });
  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; } } }); });
  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; } } }); });
  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; } } }); });
  241. 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; } } }); });
  242. 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; } } }); });
  243. 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; } } }); });
  244. 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; } } }); });
  245. 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; } } }); });
  246. 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

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

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

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

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

  251. ui-sref https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref <a ui-sref="home">Home</a> | <a ui-sref="about">About</a> ! <ul> <li

    ng-repeat="contact in contacts"> <a ui-sref="contacts.show({id: contact.id})"> {{contact.name}} </a> </li> </ul>
  252. ui-sref https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref <a ui-sref="home">Home</a> | <a ui-sref="about">About</a> ! <ul> <li

    ng-repeat="contact in contacts"> <a ui-sref="contacts.show({id: contact.id})"> {{contact.name}} </a> </li> </ul>
  253. ui-sref https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref <a ui-sref="home">Home</a> | <a ui-sref="about">About</a> ! <ul> <li

    ng-repeat="contact in contacts"> <a ui-sref="contacts.show({id: contact.id})"> {{contact.name}} </a> </li> </ul>
  254. ui-sref https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref <a ui-sref="home">Home</a> | <a ui-sref="about">About</a> ! <ul> <li

    ng-repeat="contact in contacts"> <a ui-sref="contacts.show({id: contact.id})"> {{contact.name}} </a> </li> </ul>
  255. ui-sref https://github.com/angular-ui/ui-router/wiki/Quick-Reference#ui-sref <a ui-sref="home">Home</a> | <a ui-sref="about">About</a> ! <ul> <li

    ng-repeat="contact in contacts"> <a ui-sref="contacts.show({id: contact.id})"> {{contact.name}} </a> </li> </ul>
  256. 2.0

  257. Interceptors

  258. 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; } } }); });
  259. 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; } } }); });
  260. 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; } } }); });
  261. 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
  262. 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
  263. 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
  264. 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
  265. 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
  266. 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
  267. 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
  268. 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
  269. 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
  270. 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
  271. 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
  272. Directives

  273. <input type="file" ng-model=“product.photo" simple-file-upload />

  274. 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]); }); }); } }; });
  275. 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]); }); }); } }; });
  276. 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]); }); }); } }; });
  277. 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]); }); }); } }; });
  278. 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]); }); }); } }; });
  279. 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]); }); }); } }; });
  280. 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]); }); }); } }; });
  281. 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]); }); }); } }; });
  282. 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]); }); }); } }; });
  283. transclusion

  284. <my-panel title="'Description'"> <p>Long text</p> <p>Very long text</p> <p>Very very long

    text</p> <p>Even longer text than the very very long text</p> </my-panel>
  285. <my-panel title="'Description'"> <p>Long text</p> <p>Very long text</p> <p>Very very long

    text</p> <p>Even longer text than the very very long text</p> </my-panel>
  286. <my-panel title="'Description'"> <p>Long text</p> <p>Very long text</p> <p>Very very long

    text</p> <p>Even longer text than the very very long text</p> </my-panel>
  287. <my-panel title="'Description'"> <p>Long text</p> <p>Very long text</p> <p>Very very long

    text</p> <p>Even longer text than the very very long text</p> </my-panel>
  288. <my-panel title="'Description'"> <p>Long text</p> <p>Very long text</p> <p>Very very long

    text</p> <p>Even longer text than the very very long text</p> </my-panel>
  289. ! ! <div class="panel panel-default"> <div class="panel-heading">Description</div> <div class="panel-body"> <p>Long

    text</p> <p>Very long text</p> <p>Very very long text</p> <p>Even longer text than the very very long text</p> </div> </div>
  290. ! ! <div class="panel panel-default"> <div class="panel-heading">Description</div> <div class="panel-body"> <p>Long

    text</p> <p>Very long text</p> <p>Very very long text</p> <p>Even longer text than the very very long text</p> </div> </div>
  291. ! ! <div class="panel panel-default"> <div class="panel-heading">Description</div> <div class="panel-body"> <p>Long

    text</p> <p>Very long text</p> <p>Very very long text</p> <p>Even longer text than the very very long text</p> </div> </div>
  292. 5 app.directive('myPanel', function() { return { restrict: 'E', transclude: true,

    scope: { title: '=title' }, template: '<div class="panel panel-default">' + '<div class="panel-heading">{{title}}</div>' + '<div class="panel-body" ng-transclude></div>' + '</div>' }; });
  293. 5 app.directive('myPanel', function() { return { restrict: 'E', transclude: true,

    scope: { title: '=title' }, template: '<div class="panel panel-default">' + '<div class="panel-heading">{{title}}</div>' + '<div class="panel-body" ng-transclude></div>' + '</div>' }; });
  294. 5 app.directive('myPanel', function() { return { restrict: 'E', transclude: true,

    scope: { title: '=title' }, template: '<div class="panel panel-default">' + '<div class="panel-heading">{{title}}</div>' + '<div class="panel-body" ng-transclude></div>' + '</div>' }; });
  295. 5 app.directive('myPanel', function() { return { restrict: 'E', transclude: true,

    scope: { title: '=title' }, template: '<div class="panel panel-default">' + '<div class="panel-heading">{{title}}</div>' + '<div class="panel-body" ng-transclude></div>' + '</div>' }; });
  296. 5 app.directive('myPanel', function() { return { restrict: 'E', transclude: true,

    scope: { title: '=title' }, template: '<div class="panel panel-default">' + '<div class="panel-heading">{{title}}</div>' + '<div class="panel-body" ng-transclude></div>' + '</div>' }; });
  297. 5 app.directive('myPanel', function() { return { restrict: 'E', transclude: true,

    scope: { title: '=title' }, template: '<div class="panel panel-default">' + '<div class="panel-heading">{{title}}</div>' + '<div class="panel-body" ng-transclude></div>' + '</div>' }; });
  298. 5 app.directive('myPanel', function() { return { restrict: 'E', transclude: true,

    scope: { title: '=title' }, template: '<div class="panel panel-default">' + '<div class="panel-heading">{{title}}</div>' + '<div class="panel-body" ng-transclude></div>' + '</div>' }; });
  299. 5 app.directive('myPanel', function() { return { restrict: 'E', transclude: true,

    scope: { title: '=title' }, template: '<div class="panel panel-default">' + '<div class="panel-heading">{{title}}</div>' + '<div class="panel-body" ng-transclude></div>' + '</div>' }; });
  300. 5 app.directive('myPanel', function() { return { restrict: 'E', transclude: true,

    scope: { title: '=title' }, template: '<div class="panel panel-default">' + '<div class="panel-heading">{{title}}</div>' + '<div class="panel-body" ng-transclude></div>' + '</div>' }; });
  301. <my-panel title="'Description'"> <p>Long text</p> <p>Very long text</p> <p>Very very long

    text</p> <p>Even longer text than the very very long text</p> </my-panel>
  302. ! ! <div class="panel panel-default"> <div class="panel-heading">Description</div> <div class="panel-body"> <p>Long

    text</p> <p>Very long text</p> <p>Very very long text</p> <p>Even longer text than the very very long text</p> </div> </div>
  303. ng-if vs ng-show/ng-hide 6

  304. 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') }); } }; }];
  305. 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') }); } }; }];
  306. 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') }); } }; }];
  307. 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') }); } }; }];
  308. 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') }); } }; }];
  309. 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') }); } }; }];
  310. 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') }); } }; }];
  311. 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') }); } }; }];
  312. 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') }); } }; }];
  313. 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 } }); } }; }];
  314. 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 } }); } }; }];
  315. 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 } }); } }; }];
  316. 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 } }); } }; }];
  317. 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 } }); } }; }];
  318. 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 } }); } }; }];
  319. 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 } }); } }; }];
  320. https://github.com/Pasvaz/bindonce 7

  321. 1.3.0

  322. <h1 ng-bind="::title"></h1> ! <li ng-repeat="item in ::items"> {{::item.name}} </li> https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

  323. <h1 ng-bind="::title"></h1> ! <li ng-repeat="item in ::items"> {{::item.name}} </li> https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

  324. <h1 ng-bind="::title"></h1> ! <li ng-repeat="item in ::items"> {{::item.name}} </li> https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

  325. <h1 ng-bind="::title"></h1> ! <li ng-repeat="item in ::items"> {{::item.name}} </li> https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

  326. <h1 ng-bind="::title"></h1> ! <li ng-repeat="item in ::items"> {{::item.name}} </li> https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

  327. <h1 ng-bind="::title"></h1> ! <li ng-repeat="item in ::items"> {{::item.name}} </li> https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

  328. <h1 ng-bind="::title"></h1> ! <li ng-repeat="item in ::items"> {{::item.name}} </li> https://github.com/angular/angular.js/commit/cee429f0aaebf32ef1c9aedd8447a48f163dd0a4

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

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

  332. None
  333. None
  334. @rstankov Thank you :)

  335. None