Slide 1

Slide 1 text

Radoslav Stankov PlovdivConf 17/05/2014

Slide 2

Slide 2 text

Who I am? @rstankov ! ! ! ! http://rstankov.com

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Radoslav Stankov! JavaScript event-driven architecture OpenFest 2010

Slide 6

Slide 6 text

Radoslav Stankov OpenFest 05/11/2011

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Backbone.js problems

Slide 11

Slide 11 text

Backbone.js problems

Slide 12

Slide 12 text

Backbone.js problems • Application lifecycle

Slide 13

Slide 13 text

Backbone.js problems • Application lifecycle • Conventions

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

No content

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Backbone

Slide 28

Slide 28 text

Angular

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Plugin/module system

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

injector.get(‘Person’) Person

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

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

Slide 110

Slide 110 text

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

Slide 111

Slide 111 text

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

Slide 112

Slide 112 text

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

Slide 113

Slide 113 text

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

Slide 114

Slide 114 text

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

Slide 115

Slide 115 text

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

Slide 116

Slide 116 text

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

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

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

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

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

Slide 121

Slide 121 text

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

Slide 122

Slide 122 text

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

Slide 123

Slide 123 text

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

Slide 124

Slide 124 text

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

Slide 125

Slide 125 text

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

Slide 126

Slide 126 text

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

Slide 127

Slide 127 text

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

Slide 128

Slide 128 text

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

Slide 129

Slide 129 text

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

Slide 130

Slide 130 text

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

Slide 131

Slide 131 text

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

Slide 132

Slide 132 text

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

Slide 133

Slide 133 text

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

Slide 134

Slide 134 text

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

Slide 135

Slide 135 text

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

Slide 136

Slide 136 text

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

Slide 137

Slide 137 text

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

Slide 138

Slide 138 text

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

Slide 139

Slide 139 text

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

Slide 140

Slide 140 text

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

Slide 141

Slide 141 text

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

Slide 142

Slide 142 text

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

Slide 143

Slide 143 text

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

Slide 144

Slide 144 text

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

Slide 145

Slide 145 text

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

Slide 146

Slide 146 text

Template engine

Slide 147

Slide 147 text


 


{{value}}

1

Slide 148

Slide 148 text


 


{{value}}

1

Slide 149

Slide 149 text


 


{{value}}

1

Slide 150

Slide 150 text


 


{{value}}

1

Slide 151

Slide 151 text


 


{{value}}

1

Slide 152

Slide 152 text


 


{{value}}

1

Slide 153

Slide 153 text


 


{{value}}

1

Slide 154

Slide 154 text

+ -

{{value}}

Slide 155

Slide 155 text

+ -

{{value}}

Slide 156

Slide 156 text

+ -

{{value}}

Slide 157

Slide 157 text

+ -

{{value}}

Slide 158

Slide 158 text

+ -

{{value}}

Slide 159

Slide 159 text

+ -

{{value}}

Slide 160

Slide 160 text

+ -

{{value}}

Slide 161

Slide 161 text

+ -

{{value}}

Slide 162

Slide 162 text

+ -

{{value}}

Slide 163

Slide 163 text

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

Slide 164

Slide 164 text

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

Slide 165

Slide 165 text

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

Slide 166

Slide 166 text

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

Slide 167

Slide 167 text

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

Slide 168

Slide 168 text

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

Slide 169

Slide 169 text

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

Slide 170

Slide 170 text

+ -

{{value}}

Slide 171

Slide 171 text

+ -

{{calculator.value}}

Slide 172

Slide 172 text

+ -

{{calculator.value}}

Slide 173

Slide 173 text

+ -

{{calculator.value}}

Slide 174

Slide 174 text

+ -

{{calculator.value}}

Slide 175

Slide 175 text

+ -

{{calculator.value}}

Slide 176

Slide 176 text

+ -

{{calculator.value}}

Slide 177

Slide 177 text

+ -

{{calculator.value}}

Slide 178

Slide 178 text

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

Slide 179

Slide 179 text

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

Slide 180

Slide 180 text

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

Slide 181

Slide 181 text

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

Slide 182

Slide 182 text

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

Slide 183

Slide 183 text

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

Slide 184

Slide 184 text

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

Slide 185

Slide 185 text

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

Slide 186

Slide 186 text

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

Slide 187

Slide 187 text

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

Slide 188

Slide 188 text

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

Slide 189

Slide 189 text

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

Slide 190

Slide 190 text

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

Slide 191

Slide 191 text

Demo

Slide 192

Slide 192 text

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

Slide 193

Slide 193 text

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

Slide 194

Slide 194 text

Subviews handling

Slide 195

Slide 195 text

  • {{task.text}}

Slide 196

Slide 196 text

  • {{task.text}}

Slide 197

Slide 197 text

  • {{task.text}}

Slide 198

Slide 198 text

  • {{task.text}}

Slide 199

Slide 199 text

  • {{task.text}}

Slide 200

Slide 200 text

  • {{task.text}}

Slide 201

Slide 201 text

  • {{task.text}}

Slide 202

Slide 202 text

  • {{task.text}}

Slide 203

Slide 203 text

  • {{task.text}}

Slide 204

Slide 204 text

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

Slide 205

Slide 205 text

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

Slide 206

Slide 206 text

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

Slide 207

Slide 207 text

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

Slide 208

Slide 208 text

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

Slide 209

Slide 209 text

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

Slide 210

Slide 210 text

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

Slide 211

Slide 211 text

  • {{task.text}}

Slide 212

Slide 212 text

5

Slide 213

Slide 213 text

5

Slide 214

Slide 214 text

5

Slide 215

Slide 215 text

5

Slide 216

Slide 216 text

5

Slide 217

Slide 217 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

{{description}}

Slide 218

Slide 218 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

{{description}}

Slide 219

Slide 219 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

{{description}}

Slide 220

Slide 220 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

{{description}}

Slide 221

Slide 221 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

{{description}}

Slide 222

Slide 222 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

{{description}}

Slide 223

Slide 223 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

{{description}}

Slide 224

Slide 224 text

Name

Price: $10.00 Weight: 1.2kg

Long description

Slide 225

Slide 225 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

{{description}}

Slide 226

Slide 226 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

{{description}}

Slide 227

Slide 227 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

{{description}}

Slide 228

Slide 228 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

Slide 229

Slide 229 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

Slide 230

Slide 230 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

Slide 231

Slide 231 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

Slide 232

Slide 232 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

Slide 233

Slide 233 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

Slide 234

Slide 234 text

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

Slide 235

Slide 235 text

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

Slide 236

Slide 236 text

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

Slide 237

Slide 237 text

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

Slide 238

Slide 238 text

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

Slide 239

Slide 239 text

{{name}}

Price: {{price | currency:'$' }} Weight: {{price | number: 2 }}kg

Slide 240

Slide 240 text

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

Slide 241

Slide 241 text

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

Slide 242

Slide 242 text

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

Slide 243

Slide 243 text

Routing

Slide 244

Slide 244 text

Slide 245

Slide 245 text

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

Slide 246

Slide 246 text

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

Slide 247

Slide 247 text

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

Slide 248

Slide 248 text

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

Slide 249

Slide 249 text

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

Slide 250

Slide 250 text

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

Slide 251

Slide 251 text

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

Slide 252

Slide 252 text

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

Slide 253

Slide 253 text

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

Slide 254

Slide 254 text

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

Slide 255

Slide 255 text

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

Slide 256

Slide 256 text

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

Slide 257

Slide 257 text

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

Slide 258

Slide 258 text

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

Slide 259

Slide 259 text

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

Slide 260

Slide 260 text

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

Slide 261

Slide 261 text

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

Slide 262

Slide 262 text

Testability

Slide 263

Slide 263 text

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

Slide 264

Slide 264 text

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

Slide 265

Slide 265 text

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

Slide 266

Slide 266 text

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

Slide 267

Slide 267 text

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

Slide 268

Slide 268 text

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

Slide 269

Slide 269 text

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

Slide 270

Slide 270 text

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

Slide 271

Slide 271 text

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

Slide 272

Slide 272 text

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

Slide 273

Slide 273 text

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

Slide 274

Slide 274 text

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

Slide 275

Slide 275 text

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

Slide 276

Slide 276 text

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

Slide 277

Slide 277 text

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

Slide 278

Slide 278 text

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

Slide 279

Slide 279 text

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

Slide 280

Slide 280 text

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

Slide 281

Slide 281 text

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

Slide 282

Slide 282 text

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

Slide 283

Slide 283 text

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

Slide 284

Slide 284 text

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

Slide 285

Slide 285 text

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

Slide 286

Slide 286 text

Angular problems

Slide 287

Slide 287 text

Angular problems

Slide 288

Slide 288 text

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

Slide 289

Slide 289 text

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

Slide 290

Slide 290 text

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

Slide 291

Slide 291 text

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

Slide 292

Slide 292 text

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

Slide 293

Slide 293 text

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

Slide 294

Slide 294 text

No content

Slide 295

Slide 295 text

@rstankov Thanks :)

Slide 296

Slide 296 text

Questions?