Angular JS

Angular JS

Introduction to Angular JS, I gave at PlovdivConf 2014

7a0e72a6f55811246bb5d9a946fd2e49?s=128

Radoslav Stankov

May 17, 2014
Tweet

Transcript

  1. 3.
  2. 4.
  3. 7.
  4. 8.
  5. 9.
  6. 17.
  7. 18.

    Backbone.js problems • Application lifecycle • Conventions • Plugin/module system

    • Template engine • Subviews handling • Routing • Testability
  8. 19.
  9. 20.
  10. 21.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Недостатъци на Backbone.js
  11. 22.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Недостатъци на Backbone.js Angular
  12. 23.

    • Application lifecycle! • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  13. 24.
  14. 25.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  15. 26.

    • Application lifecycle • Conventions! • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  16. 27.
  17. 28.
  18. 29.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  19. 30.

    • Application lifecycle • Conventions • Plugin/module system! • Template

    engine • Subviews handling • Routing • Testability Angular
  20. 76.

    (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  21. 77.

    (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  22. 78.

    (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  23. 79.

    (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  24. 80.

    (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  25. 81.

    (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  26. 82.

    (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  27. 83.

    (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  28. 84.

    (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  29. 97.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  30. 98.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  31. 99.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  32. 100.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  33. 101.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  34. 102.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  35. 103.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  36. 104.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  37. 105.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  38. 106.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  39. 107.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  40. 108.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  41. 109.

    app.factory('Person', function($window) { var name = ''; ! return {

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  42. 116.

    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); }; });
  43. 117.

    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); }; });
  44. 118.

    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); }; });
  45. 119.

    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); }; });
  46. 120.

    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); }; });
  47. 123.

    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); } }; } });
  48. 124.

    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); } }; } });
  49. 125.

    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); } }; } });
  50. 126.

    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); } }; } });
  51. 127.

    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); } }; } });
  52. 128.

    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); } }; } });
  53. 129.

    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); } }; } });
  54. 130.

    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); } }; } });
  55. 131.

    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); } }; } });
  56. 144.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  57. 145.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine! • Subviews handling • Routing • Testability Angular
  58. 163.

    app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  59. 164.

    app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  60. 165.

    app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  61. 166.

    app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  62. 167.

    app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  63. 168.

    app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  64. 169.

    app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  65. 179.
  66. 180.
  67. 181.
  68. 182.
  69. 183.
  70. 184.
  71. 185.
  72. 191.
  73. 192.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  74. 193.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling! • Routing • Testability Angular
  75. 195.

    <body ng-controller="demoCtrl"> <article> <ul> <li ng-repeat="task in tasks">{{task.text}}</li> <li> <form

    ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body>
  76. 196.

    <body ng-controller="demoCtrl"> <article> <ul> <li ng-repeat="task in tasks">{{task.text}}</li> <li> <form

    ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body>
  77. 197.

    <body ng-controller="demoCtrl"> <article> <ul> <li ng-repeat="task in tasks">{{task.text}}</li> <li> <form

    ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body>
  78. 198.

    <body ng-controller="demoCtrl"> <article> <ul> <li ng-repeat="task in tasks">{{task.text}}</li> <li> <form

    ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body>
  79. 199.

    <body ng-controller="demoCtrl"> <article> <ul> <li ng-repeat="task in tasks">{{task.text}}</li> <li> <form

    ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body>
  80. 200.

    <body ng-controller="demoCtrl"> <article> <ul> <li ng-repeat="task in tasks">{{task.text}}</li> <li> <form

    ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body>
  81. 201.

    <body ng-controller="demoCtrl"> <article> <ul> <li ng-repeat="task in tasks">{{task.text}}</li> <li> <form

    ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body>
  82. 202.

    <body ng-controller="demoCtrl"> <article> <ul> <li ng-repeat="task in tasks">{{task.text}}</li> <li> <form

    ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body>
  83. 203.

    <body ng-controller="demoCtrl"> <article> <ul> <li ng-repeat="task in tasks">{{task.text}}</li> <li> <form

    ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body>
  84. 204.

    app.controller('demoCtrl', function($scope) { $scope.tasks = []; $scope.newTask = ""; $scope.createTask

    = function() { if ($scope.newTask.length > 0) { $scope.tasks.push({name: $scope.newTask}); $scope.newTask = ""; } }; }); 4
  85. 205.

    app.controller('demoCtrl', function($scope) { $scope.tasks = []; $scope.newTask = ""; $scope.createTask

    = function() { if ($scope.newTask.length > 0) { $scope.tasks.push({name: $scope.newTask}); $scope.newTask = ""; } }; }); 4
  86. 206.

    app.controller('demoCtrl', function($scope) { $scope.tasks = []; $scope.newTask = ""; $scope.createTask

    = function() { if ($scope.newTask.length > 0) { $scope.tasks.push({name: $scope.newTask}); $scope.newTask = ""; } }; }); 4
  87. 207.

    app.controller('demoCtrl', function($scope) { $scope.tasks = []; $scope.newTask = ""; $scope.createTask

    = function() { if ($scope.newTask.length > 0) { $scope.tasks.push({name: $scope.newTask}); $scope.newTask = ""; } }; }); 4
  88. 208.

    app.controller('demoCtrl', function($scope) { $scope.tasks = []; $scope.newTask = ""; $scope.createTask

    = function() { if ($scope.newTask.length > 0) { $scope.tasks.push({name: $scope.newTask}); $scope.newTask = ""; } }; }); 4
  89. 209.

    app.controller('demoCtrl', function($scope) { $scope.tasks = []; $scope.newTask = ""; $scope.createTask

    = function() { if ($scope.newTask.length > 0) { $scope.tasks.push({name: $scope.newTask}); $scope.newTask = ""; } }; }); 4
  90. 210.

    app.controller('demoCtrl', function($scope) { $scope.tasks = []; $scope.newTask = ""; $scope.createTask

    = function() { if ($scope.newTask.length > 0) { $scope.tasks.push({name: $scope.newTask}); $scope.newTask = ""; } }; }); 4
  91. 211.

    <body ng-controller="demoCtrl"> <article> <ul> <li ng-repeat="task in tasks">{{task.text}}</li> <li> <form

    ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body>
  92. 212.

    <body ng-controller="demoCtrl"> <header> <input type="search" ng-model=“search" placeholder="filter" /> </header> <article>

    <ul> <li ng-repeat="task in tasks | filter:search”>{{task.text}}</ <li> <form ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body> 5
  93. 213.

    <body ng-controller="demoCtrl"> <header> <input type="search" ng-model=“search" placeholder="filter" /> </header> <article>

    <ul> <li ng-repeat="task in tasks | filter:search”>{{task.text}}</ <li> <form ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body> 5
  94. 214.

    <body ng-controller="demoCtrl"> <header> <input type="search" ng-model=“search" placeholder="filter" /> </header> <article>

    <ul> <li ng-repeat="task in tasks | filter:search”>{{task.text}}</ <li> <form ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body> 5
  95. 215.

    <body ng-controller="demoCtrl"> <header> <input type="search" ng-model=“search" placeholder="filter" /> </header> <article>

    <ul> <li ng-repeat="task in tasks | filter:search”>{{task.text}}</ <li> <form ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body> 5
  96. 216.

    <body ng-controller="demoCtrl"> <header> <input type="search" ng-model=“search" placeholder="filter" /> </header> <article>

    <ul> <li ng-repeat="task in tasks | filter:search”>{{task.text}}</ <li> <form ng-submit="createTask();"> <input type="text" ng-model="newTask" /> </form> </li> </ul> </article> </body> 5
  97. 217.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p>{{description}}</p> </article>
  98. 218.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p>{{description}}</p> </article>
  99. 219.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p>{{description}}</p> </article>
  100. 220.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p>{{description}}</p> </article>
  101. 221.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p>{{description}}</p> </article>
  102. 222.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p>{{description}}</p> </article>
  103. 223.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p>{{description}}</p> </article>
  104. 225.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p>{{description}}</p> </article>
  105. 226.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p>{{description}}</p> </article>
  106. 227.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p>{{description}}</p> </article>
  107. 228.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p ng-bind-html="description"></p> </article>
  108. 229.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p ng-bind-html="description"></p> </article>
  109. 230.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p ng-bind-html="description"></p> </article>
  110. 231.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p ng-bind-html=“description | simpleFormat"></p> </article>
  111. 232.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p ng-bind-html=“description | simpleFormat"></p> </article>
  112. 233.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p ng-bind-html=“description | simpleFormat"></p> </article>
  113. 239.

    <article> <h1>{{name}}</h1> <time>{{createdAt | date:'dd.MM.yyyy'}}</time> <strong>Price: {{price | currency:'$' }}</strong>

    <strong>Weight: {{price | number: 2 }}kg</strong> <p ng-bind-html=“description | simpleFormat"></p> </article>
  114. 241.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  115. 242.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing! • Testability Angular
  116. 243.
  117. 245.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  118. 246.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  119. 247.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  120. 248.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  121. 249.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  122. 250.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  123. 251.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  124. 252.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  125. 253.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  126. 254.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  127. 255.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  128. 256.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  129. 257.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  130. 258.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  131. 259.

    app.config(function($routeProvider) { $routeProvider.when('/people/:id', { templateUrl: 'people/show.html', controller: 'peopleCtrl', resolve: {

    person: function($routeParams, People) { return People.get(id: $routeParams.id).$promise; } } }); });
  132. 260.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  133. 261.

    • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  134. 263.

    describe('myDirective', function() { var $compile; var $rootScope; ! beforeEach(module('myApp')); !

    beforeEach(inject(function(_$compile_, _$rootScope_){ $compile = _$compile_; $rootScope = _$rootScope_; })); ! it('replaces the element with the appropriate content', function() { var element = $compile("<my-directive></my-directive>")($rootScope); ! $rootScope.$digest(); ! expect(element.html()).toContain('PlovdivConf Part 2'); }); });
  135. 264.

    describe('myDirective', function() { var $compile; var $rootScope; ! beforeEach(module('myApp')); !

    beforeEach(inject(function(_$compile_, _$rootScope_){ $compile = _$compile_; $rootScope = _$rootScope_; })); ! it('replaces the element with the appropriate content', function() { var element = $compile("<my-directive></my-directive>")($rootScope); ! $rootScope.$digest(); ! expect(element.html()).toContain('PlovdivConf Part 2'); }); });
  136. 265.

    describe('myDirective', function() { var $compile; var $rootScope; ! beforeEach(module('myApp')); !

    beforeEach(inject(function(_$compile_, _$rootScope_){ $compile = _$compile_; $rootScope = _$rootScope_; })); ! it('replaces the element with the appropriate content', function() { var element = $compile("<my-directive></my-directive>")($rootScope); ! $rootScope.$digest(); ! expect(element.html()).toContain('PlovdivConf Part 2'); }); });
  137. 266.

    describe('myDirective', function() { var $compile; var $rootScope; ! beforeEach(module('myApp')); !

    beforeEach(inject(function(_$compile_, _$rootScope_){ $compile = _$compile_; $rootScope = _$rootScope_; })); ! it('replaces the element with the appropriate content', function() { var element = $compile("<my-directive></my-directive>")($rootScope); ! $rootScope.$digest(); ! expect(element.html()).toContain('PlovdivConf Part 2'); }); });
  138. 267.

    describe('myDirective', function() { var $compile; var $rootScope; ! beforeEach(module('myApp')); !

    beforeEach(inject(function(_$compile_, _$rootScope_){ $compile = _$compile_; $rootScope = _$rootScope_; })); ! it('replaces the element with the appropriate content', function() { var element = $compile("<my-directive></my-directive>")($rootScope); ! $rootScope.$digest(); ! expect(element.html()).toContain('PlovdivConf Part 2'); }); });
  139. 268.

    describe('myDirective', function() { var $compile; var $rootScope; ! beforeEach(module('myApp')); !

    beforeEach(inject(function(_$compile_, _$rootScope_){ $compile = _$compile_; $rootScope = _$rootScope_; })); ! it('replaces the element with the appropriate content', function() { var element = $compile("<my-directive></my-directive>")($rootScope); ! $rootScope.$digest(); ! expect(element.html()).toContain('PlovdivConf Part 2'); }); });
  140. 269.

    describe('myDirective', function() { var $compile; var $rootScope; ! beforeEach(module('myApp')); !

    beforeEach(inject(function(_$compile_, _$rootScope_){ $compile = _$compile_; $rootScope = _$rootScope_; })); ! it('replaces the element with the appropriate content', function() { var element = $compile("<my-directive></my-directive>")($rootScope); ! $rootScope.$digest(); ! expect(element.html()).toContain('PlovdivConf Part 2'); }); });
  141. 270.

    describe('myDirective', function() { var $compile; var $rootScope; ! beforeEach(module('myApp')); !

    beforeEach(inject(function(_$compile_, _$rootScope_){ $compile = _$compile_; $rootScope = _$rootScope_; })); ! it('replaces the element with the appropriate content', function() { var element = $compile("<my-directive></my-directive>")($rootScope); ! $rootScope.$digest(); ! expect(element.html()).toContain('PlovdivConf Part 2'); }); });
  142. 271.

    describe('myDirective', function() { var $compile; var $rootScope; ! beforeEach(module('myApp')); !

    beforeEach(inject(function(_$compile_, _$rootScope_){ $compile = _$compile_; $rootScope = _$rootScope_; })); ! it('replaces the element with the appropriate content', function() { var element = $compile("<my-directive></my-directive>")($rootScope); ! $rootScope.$digest(); ! expect(element.html()).toContain('PlovdivConf Part 2'); }); });
  143. 272.

    var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  144. 273.

    var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  145. 274.

    var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  146. 275.

    var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  147. 276.

    var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  148. 277.

    var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  149. 278.

    var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  150. 279.

    var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  151. 280.

    var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  152. 281.

    var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  153. 282.

    var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  154. 283.

    Angular • Application lifecycle • Conventions • Plugin/module system •

    Template engine • Subviews handling • Routing • Testability
  155. 285.

    … even more • angular-resource • angular-animation • angular-i18n •

    angular-ui-router • angular-hammer • angular-bindonce • …
  156. 291.

    Angular problems • Много магия • Доста логика в HTML

    • Performance проблеми • Learning curve
  157. 292.

    Angular problems • Много магия • Доста логика в HTML

    • Performance проблеми • Learning curve • Добри практики
  158. 294.
  159. 296.