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

Angular JS

Angular JS

Introduction to Angular JS, I gave at PlovdivConf 2014

Radoslav Stankov

May 17, 2014
Tweet

More Decks by Radoslav Stankov

Other Decks in Technology

Transcript

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

    • Template engine • Subviews handling • Routing • Testability
  2. • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Недостатъци на Backbone.js
  3. • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Недостатъци на Backbone.js Angular
  4. • Application lifecycle! • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  5. • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  6. • Application lifecycle • Conventions! • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  7. • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  8. • Application lifecycle • Conventions • Plugin/module system! • Template

    engine • Subviews handling • Routing • Testability Angular
  9. (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  10. (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  11. (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  12. (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  13. (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  14. (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  15. (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  16. (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  17. (function() { function Product($resource) { return $resource("/api/products/:id", {id: '@id'}); }

    ! Product.$inject = ['$resource'] ! app.service('Product', Product); })();
  18. app.factory('Person', function($window) { var name = ''; ! return {

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

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

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

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

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

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

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

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

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

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

    setName: function(newName) { name = newName; }, getName: function() { return name; }, say: function(text) { $window.alert(name + ' - ' + text); } } });
  29. 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. 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. 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); }; });
  32. 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); }; });
  33. 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); }; });
  34. 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); }; });
  35. 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); }; });
  36. 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); } }; } });
  37. 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); } }; } });
  38. 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); } }; } });
  39. 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); } }; } });
  40. 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); } }; } });
  41. 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); } }; } });
  42. 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); } }; } });
  43. 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); } }; } });
  44. 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); } }; } });
  45. • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  46. • Application lifecycle • Conventions • Plugin/module system • Template

    engine! • Subviews handling • Routing • Testability Angular
  47. app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  48. app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  49. app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  50. app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  51. app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  52. app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  53. app.controller('demoCtrl', function($scope) { $scope.value = 0; $scope.increase = function() {

    $scope.value += 1; }; $scope.decrease = function() { $scope.value -= 1; }; }); 2
  54. • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  55. • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling! • Routing • Testability Angular
  56. <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>
  57. <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>
  58. <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>
  59. <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>
  60. <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>
  61. <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>
  62. <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>
  63. <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>
  64. <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>
  65. 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
  66. 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
  67. 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
  68. 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
  69. 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
  70. 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
  71. 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
  72. <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>
  73. <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
  74. <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
  75. <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
  76. <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
  77. <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
  78. <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>
  79. <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>
  80. <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>
  81. <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>
  82. <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>
  83. <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>
  84. <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>
  85. <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>
  86. <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>
  87. <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>
  88. <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>
  89. <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>
  90. <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>
  91. <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>
  92. <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>
  93. <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>
  94. <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>
  95. • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  96. • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing! • Testability Angular
  97. 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; } } }); });
  98. 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; } } }); });
  99. 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; } } }); });
  100. 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; } } }); });
  101. 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; } } }); });
  102. 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; } } }); });
  103. 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; } } }); });
  104. 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; } } }); });
  105. 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; } } }); });
  106. 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; } } }); });
  107. 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; } } }); });
  108. 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; } } }); });
  109. 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; } } }); });
  110. 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; } } }); });
  111. 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; } } }); });
  112. • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  113. • Application lifecycle • Conventions • Plugin/module system • Template

    engine • Subviews handling • Routing • Testability Angular
  114. 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'); }); });
  115. 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'); }); });
  116. 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'); }); });
  117. 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'); }); });
  118. 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'); }); });
  119. 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'); }); });
  120. 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'); }); });
  121. 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'); }); });
  122. 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'); }); });
  123. var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  124. var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  125. var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  126. var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  127. var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  128. var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  129. var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  130. var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  131. var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  132. var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  133. var app = angular.module('myApp', []); ! app.directive('myDirective', function () {

    return { restrict: 'E', replace: true, template: 'PlovdivConf Part {{1 + 1}}' }; });
  134. Angular • Application lifecycle • Conventions • Plugin/module system •

    Template engine • Subviews handling • Routing • Testability
  135. … even more • angular-resource • angular-animation • angular-i18n •

    angular-ui-router • angular-hammer • angular-bindonce • …
  136. Angular problems • Много магия • Доста логика в HTML

    • Performance проблеми • Learning curve
  137. Angular problems • Много магия • Доста логика в HTML

    • Performance проблеми • Learning curve • Добри практики