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. Radoslav Stankov

    PlovdivConf 17/05/2014

    View Slide

  2. Who I am?
    @rstankov

    !
    !
    !
    !
    http://rstankov.com

    View Slide

  3. View Slide

  4. View Slide

  5. Radoslav Stankov!
    JavaScript event-driven architecture
    OpenFest 2010

    View Slide

  6. Radoslav Stankov
    OpenFest 05/11/2011

    View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. Backbone.js problems

    View Slide

  11. Backbone.js problems

    View Slide

  12. Backbone.js problems
    • Application lifecycle

    View Slide

  13. Backbone.js problems
    • Application lifecycle
    • Conventions

    View Slide

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

    View Slide

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

    View Slide

  16. Backbone.js problems
    • Application lifecycle
    • Conventions
    • Plugin/module system
    • Template engine
    • Subviews handling

    View Slide

  17. Backbone.js problems
    • Application lifecycle
    • Conventions
    • Plugin/module system
    • Template engine
    • Subviews handling
    • Routing

    View Slide

  18. Backbone.js problems
    • Application lifecycle
    • Conventions
    • Plugin/module system
    • Template engine
    • Subviews handling
    • Routing
    • Testability

    View Slide

  19. View Slide

  20. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  24. View Slide

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

    View Slide

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

    View Slide

  27. Backbone

    View Slide

  28. Angular

    View Slide

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

    View Slide

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

    View Slide

  31. Plugin/module system

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  35. app = angular.module('Demo', ['ngResource', 'simpleFormat']);

    View Slide

  36. app = angular.module('Demo', ['ngResource', 'simpleFormat']);

    View Slide

  37. app = angular.module('Demo', ['ngResource', 'simpleFormat']);

    View Slide

  38. app.controller('demoCtrl', function($scope, Calculator) {
    $scope.calculator = new Calculator(0);
    });

    View Slide

  39. app.controller('demoCtrl', function($scope, Calculator) {
    $scope.calculator = new Calculator(0);
    });

    View Slide

  40. app.controller('demoCtrl', function($scope, Calculator) {
    $scope.calculator = new Calculator(0);
    });

    View Slide

  41. app.controller('demoCtrl', function($scope, Calculator) {
    $scope.calculator = new Calculator(0);
    });

    View Slide

  42. app.controller('demoCtrl', function($scope, Calculator) {
    $scope.calculator = new Calculator(0);
    });

    View Slide

  43. app.controller('demoCtrl', function($scope, Calculator) {
    $scope.calculator = new Calculator(0);
    });

    View Slide

  44. app.controller('demoCtrl', function($scope, Calculator) {
    $scope.calculator = new Calculator(0);
    });

    View Slide

  45. app.controller('demoCtrl', function($scope, Calculator) {
    $scope.calculator = new Calculator(0);
    });

    View Slide

  46. app.controller('demoCtrl', function($scope, Calculator) {
    $scope.calculator = new Calculator(0);
    });

    View Slide

  47. app.controller('demoCtrl', function($scope, Calculator) {
    $scope.calculator = new Calculator(0);
    });

    View Slide

  48. app.controller('demoCtrl', function($scope, Calculator) {
    $scope.calculator = new Calculator(0);
    });

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  58. app.controller('demoController', function($scope) {
    $scope.sayHi = function() {
    window.alert('Hi');
    }
    });

    View Slide

  59. app.controller('demoController', function($scope) {
    $scope.sayHi = function() {
    window.alert('Hi');
    }
    });

    View Slide

  60. app.controller('demoController', function($scope) {
    $scope.sayHi = function() {
    window.alert('Hi');
    }
    });

    View Slide

  61. app.controller('demoController', function($scope) {
    $scope.sayHi = function() {
    window.alert('Hi');
    }
    });

    View Slide

  62. app.controller('demoController', function($scope) {
    $scope.sayHi = function() {
    window.alert('Hi');
    }
    });

    View Slide

  63. app.controller('demoController', function($scope, $window) {
    $scope.sayHi = function() {
    $window.alert('Hi');
    }
    });

    View Slide

  64. app.controller('demoController', function($scope, $window) {
    $scope.sayHi = function() {
    $window.alert('Hi');
    }
    });

    View Slide

  65. app.controller('demoController', function($scope, $window) {
    $scope.sayHi = function() {
    $window.alert('Hi');
    }
    });

    View Slide

  66. app.controller('demoController', function($scope, $window) {
    $scope.sayHi = function() {
    $window.alert('Hi');
    }
    });

    View Slide

  67. app.controller('demoController', function($scope, $window) {
    $scope.sayHi = function() {
    $window.alert('Hi');
    }
    });

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  96. injector.get(‘Person’)
    Person

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

  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);
    }
    }
    });

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  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);
    };
    });

    View Slide

  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);
    };
    });

    View Slide

  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);
    };
    });

    View Slide

  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);
    };
    });

    View Slide

  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);
    };
    });

    View Slide

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

    View Slide

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

    View Slide

  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);
    }
    };
    }
    });

    View Slide

  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);
    }
    };
    }
    });

    View Slide

  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);
    }
    };
    }
    });

    View Slide

  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);
    }
    };
    }
    });

    View Slide

  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);
    }
    };
    }
    });

    View Slide

  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);
    }
    };
    }
    });

    View Slide

  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);
    }
    };
    }
    });

    View Slide

  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);
    }
    };
    }
    });

    View Slide

  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);
    }
    };
    }
    });

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  146. Template engine

    View Slide







  147. {{value}}



    1

    View Slide







  148. {{value}}



    1

    View Slide







  149. {{value}}



    1

    View Slide







  150. {{value}}



    1

    View Slide







  151. {{value}}



    1

    View Slide







  152. {{value}}



    1

    View Slide







  153. {{value}}



    1

    View Slide




  154. +
    -


    {{value}}



    View Slide




  155. +
    -


    {{value}}



    View Slide




  156. +
    -


    {{value}}



    View Slide




  157. +
    -


    {{value}}



    View Slide




  158. +
    -


    {{value}}



    View Slide




  159. +
    -


    {{value}}



    View Slide




  160. +
    -


    {{value}}



    View Slide




  161. +
    -


    {{value}}



    View Slide




  162. +
    -


    {{value}}



    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide




  170. +
    -


    {{value}}



    View Slide




  171. +
    -


    {{calculator.value}}



    View Slide




  172. +
    -


    {{calculator.value}}



    View Slide




  173. +
    -


    {{calculator.value}}



    View Slide




  174. +
    -


    {{calculator.value}}



    View Slide




  175. +
    -


    {{calculator.value}}



    View Slide




  176. +
    -


    {{calculator.value}}



    View Slide




  177. +
    -


    {{calculator.value}}



    View Slide

  178. app.value('Calculator', {
    value: 0
    });

    View Slide

  179. app.controller('actionsCtrl', function($scope, Calculator) {
    $scope.increase = function() {
    Calculator.value += 1;
    };
    $scope.decrease = function() {
    Calculator.value -= 1;
    };
    });

    View Slide

  180. app.controller('actionsCtrl', function($scope, Calculator) {
    $scope.increase = function() {
    Calculator.value += 1;
    };
    $scope.decrease = function() {
    Calculator.value -= 1;
    };
    });

    View Slide

  181. app.controller('actionsCtrl', function($scope, Calculator) {
    $scope.increase = function() {
    Calculator.value += 1;
    };
    $scope.decrease = function() {
    Calculator.value -= 1;
    };
    });

    View Slide

  182. app.controller('actionsCtrl', function($scope, Calculator) {
    $scope.increase = function() {
    Calculator.value += 1;
    };
    $scope.decrease = function() {
    Calculator.value -= 1;
    };
    });

    View Slide

  183. app.controller('actionsCtrl', function($scope, Calculator) {
    $scope.increase = function() {
    Calculator.value += 1;
    };
    $scope.decrease = function() {
    Calculator.value -= 1;
    };
    });

    View Slide

  184. app.controller('actionsCtrl', function($scope, Calculator) {
    $scope.increase = function() {
    Calculator.value += 1;
    };
    $scope.decrease = function() {
    Calculator.value -= 1;
    };
    });

    View Slide

  185. app.controller('actionsCtrl', function($scope, Calculator) {
    $scope.increase = function() {
    Calculator.value += 1;
    };
    $scope.decrease = function() {
    Calculator.value -= 1;
    };
    });

    View Slide

  186. app.controller('displayCtrl', function($scope, Calculator) {
    $scope.calculator = Calculator
    });
    3

    View Slide

  187. app.controller('displayCtrl', function($scope, Calculator) {
    $scope.calculator = Calculator
    });
    3

    View Slide

  188. app.controller('displayCtrl', function($scope, Calculator) {
    $scope.calculator = Calculator
    });
    3

    View Slide

  189. app.controller('displayCtrl', function($scope, Calculator) {
    $scope.calculator = Calculator
    });
    3

    View Slide

  190. app.controller('displayCtrl', function($scope, Calculator) {
    $scope.calculator = Calculator
    });
    3

    View Slide

  191. Demo

    View Slide

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

    View Slide

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

    View Slide

  194. Subviews handling

    View Slide




  195. {{task.text}}








    View Slide




  196. {{task.text}}








    View Slide




  197. {{task.text}}








    View Slide




  198. {{task.text}}








    View Slide




  199. {{task.text}}








    View Slide




  200. {{task.text}}








    View Slide




  201. {{task.text}}








    View Slide




  202. {{task.text}}








    View Slide




  203. {{task.text}}








    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide




  211. {{task.text}}








    View Slide














  212. 5

    View Slide














  213. 5

    View Slide














  214. 5

    View Slide














  215. 5

    View Slide














  216. 5

    View Slide


  217. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg
    {{description}}

    View Slide


  218. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg
    {{description}}

    View Slide


  219. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg
    {{description}}

    View Slide


  220. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg
    {{description}}

    View Slide


  221. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg
    {{description}}

    View Slide


  222. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg
    {{description}}

    View Slide


  223. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg
    {{description}}

    View Slide


  224. Name
    05.05.2014
    Price: $10.00
    Weight: 1.2kg
    Long description

    View Slide


  225. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg
    {{description}}

    View Slide


  226. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg
    {{description}}

    View Slide


  227. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg
    {{description}}

    View Slide


  228. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg


    View Slide


  229. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg


    View Slide


  230. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg


    View Slide


  231. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg


    View Slide


  232. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg


    View Slide


  233. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg


    View Slide

  234. app.filter('simpleFormat', function() {
    return function(text) {
    return (text || '').replace(/\n/g, "\n
    ");
    };
    });

    View Slide

  235. app.filter('simpleFormat', function() {
    return function(text) {
    return (text || '').replace(/\n/g, "\n
    ");
    };
    });

    View Slide

  236. app.filter('simpleFormat', function() {
    return function(text) {
    return (text || '').replace(/\n/g, "\n
    ");
    };
    });

    View Slide

  237. app.filter('simpleFormat', function() {
    return function(text) {
    return (text || '').replace(/\n/g, "\n
    ");
    };
    });

    View Slide

  238. app.filter('simpleFormat', function() {
    return function(text) {
    return (text || '').replace(/\n/g, "\n
    ");
    };
    });

    View Slide


  239. {{name}}
    {{createdAt | date:'dd.MM.yyyy'}}
    Price: {{price | currency:'$' }}
    Weight: {{price | number: 2 }}kg


    View Slide

  240. bower install angular-simple-format
    https://github.com/RStankov/angular-simple-format

    View Slide

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

    View Slide

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

    View Slide

  243. Routing

    View Slide


  244. View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

  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;
    }
    }
    });
    });

    View Slide

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

    View Slide

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

    View Slide

  262. Testability

    View Slide

  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("")($rootScope);
    !
    $rootScope.$digest();
    !
    expect(element.html()).toContain('PlovdivConf Part 2');
    });
    });

    View Slide

  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("")($rootScope);
    !
    $rootScope.$digest();
    !
    expect(element.html()).toContain('PlovdivConf Part 2');
    });
    });

    View Slide

  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("")($rootScope);
    !
    $rootScope.$digest();
    !
    expect(element.html()).toContain('PlovdivConf Part 2');
    });
    });

    View Slide

  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("")($rootScope);
    !
    $rootScope.$digest();
    !
    expect(element.html()).toContain('PlovdivConf Part 2');
    });
    });

    View Slide

  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("")($rootScope);
    !
    $rootScope.$digest();
    !
    expect(element.html()).toContain('PlovdivConf Part 2');
    });
    });

    View Slide

  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("")($rootScope);
    !
    $rootScope.$digest();
    !
    expect(element.html()).toContain('PlovdivConf Part 2');
    });
    });

    View Slide

  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("")($rootScope);
    !
    $rootScope.$digest();
    !
    expect(element.html()).toContain('PlovdivConf Part 2');
    });
    });

    View Slide

  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("")($rootScope);
    !
    $rootScope.$digest();
    !
    expect(element.html()).toContain('PlovdivConf Part 2');
    });
    });

    View Slide

  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("")($rootScope);
    !
    $rootScope.$digest();
    !
    expect(element.html()).toContain('PlovdivConf Part 2');
    });
    });

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  284. https://github.com/RStankov/talk-angular-js
    The code commit by commit

    View Slide

  285. … even more
    • angular-resource
    • angular-animation
    • angular-i18n
    • angular-ui-router
    • angular-hammer
    • angular-bindonce
    • …

    View Slide

  286. Angular problems

    View Slide

  287. Angular problems

    View Slide

  288. Angular problems
    • Много магия

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  294. View Slide

  295. @rstankov
    Thanks :)

    View Slide

  296. Questions?

    View Slide