-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
176 lines (152 loc) · 12.5 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><title>Service Patterns in AngularJS</title><meta name="description" content="An overview of service patterns in AngularJS"><meta name="author" content="Jeremy Mason"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><link rel="stylesheet" href="css/reveal.min.css"><link rel="stylesheet" href="css/theme/default.css" id="theme"><link rel="stylesheet" href="css/custom.css"><!-- For syntax highlighting --><link rel="stylesheet" href="lib/css/zenburn.css"><!-- If the query includes 'print-pdf', use the PDF print sheet --><script type="text/javascript">document.write( '<link rel="stylesheet" href="css/print/' + ( window.location.search.match( /print-pdf/gi ) ? 'pdf' : 'paper' ) + '.css" type="text/css" media="print">' );
</script><!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]--></head><body><div class="reveal"><div class="slides"><section><section><h2>Service Patterns in AngularJS</h2><p>by Jeremy Mason</p><br><div class="break"><h3>Download the slides</h3><div>https://github.com/jeremyalan/AngularJS-ServicePatterns</div></div><div class="break"><h3>Contact me</h3><div><span>jeremyalan@gmail.com</span><br><span>Twitter @jeremyalan</span></div></div></section><section><h2>Sponsors</h2><img src="slides/images/sponsors.png" height="60%"></section><section><h1>Quick Poll</h1></section></section><section><section><h2>Angular components</h2><ul><li>Modules</li><li>Services</li><li>Controllers</li><li>Directives</li><li>Filters</li></ul></section><section><h2>Modules</h2><p><span>Combines related components of your application</span><br><span>into a single, reusable component</span></p><div class="break"></div><ul><li>All other components reside within modules</li><li>Modules can depend on other modules</li><li>Delayed initialization</li><li><div><span>Modules are </span><span class="underline">NOT</span><span> loaded async</span></div><div class="small"><span>- still need RequireJS or similar</span></div></li></ul></section><section><h2>Modules</h2><div><span>Create a new module</span><pre>angular.module('myModule', ['dep1', 'dep2']);
</pre></div><div class="break"></div><div><span>Retrieve an existing module</span><pre>angular.module('myModule');
// Order of execution matters!
// This fails if module has not been declared yet
</pre></div><div class="break"></div><div><span>Initialize a module</span><pre>angular.module('myModule')
.config(function () { ... })
.run(function () { ... })</pre><span class="small">More on this later...</span></div></section></section><section><section><h2>Services</h2><p><span>Custom objects that are shared across your application</span></p><div class="break"></div><ul><li>Singletons</li><li><span>Injectable </span><span class="small">> let's dig a little deeper...</span></li></ul></section><section><h2>Dependency Injection</h2><div><span>Allows services to be passed into a dependent module,</span><br><span>such as a controller, directive, or another service</span></div><div class="break"></div><h3>Why should we care?</h3><ul><li>Supports testability</li><li>Discourages the use of global variables</li><li><div>Allows for complex configuration scenarios</div><div class="text-center small">More on this later...</div></li></ul></section><section><h2>Dependencies</h2><h3>Inline Declaration</h3><div class="break"></div><ul><li>Angular calls .toString() on constructor function</li><li><span class="underline">DOES NOT WORK</span><span> with minified code</span></li></ul><pre>function MyService(<span class="highlight">$http</span>) {
...
};
angular.module('myModule')
.service('$myService', MyService);
</pre></section><section><h2>Dependencies</h2><h3>Array arguments</h3><div class="break"></div><ul><li>Uses string values to counteract minification</li><li>Similar syntax to other module components (directives)</li><li>Class declaration tightly coupled to module registration</li></ul><pre>function MyService($http) {
...
};
angular.module('myModule')
.service('$myService', <span class="highlight">['$http', MyService]</span>);</pre></section><section><h2>Dependencies</h2><h3><span class="no-upper">$inject</span></h3><ul><li>Use string values to counteract minification</li><li>$inject is tied to class declaration, not module registration</li></ul><pre>function MyService($http) {
...
};
<span class="highlight">MyService.$inject = ['$http'];</span>
angular.module('myModule')
.service('$myService', MyService);</pre></section><section><h2><span class="no-upper">$injector</span></h2><div>Angular's implementation of the Service Locator pattern</div><div class="break"></div><ul><li>Created automatically during app initialization</li><li><span>Can be used at runtime against any function</span><br><pre>$injector.invoke(function (dep) { ... });</pre></li><li><span>Or, create your own!</span><br><pre>var injector = angular.injector(['ng', 'mod1']);</pre></li></ul></section></section><section><section><h2>Services</h2><ul><li><b>Constant/Value</b><br><span class="small">- Pass an instance</span></li><li><b>Service</b><br><span class="small">- Pass a constructor function</span></li><li><b>Factory</b><br><span class="small">- Pass a function that returns an instance</span></li><li><b>Provider</b><br><span class="small">- Pass a function that returns a "service object"</span></li><li><b>Decorator</b><br><span class="small">- Transform or replace an instance during creation</span></li></ul></section><section><h2>Constant</h2><div><span>module.constant(...)</span></div><pre>angular.module('api')
.constant('$apiKey', <span class="highlight">'1234567890abcdef'</span>);</pre></section><section><h2>Service</h2><div><span>module.service(...)</span></div><pre>function PersonService($http) {
this.create = function (info) {
return $http.post('/api/person', info);
};
}
angular.module('api')
.service('$person', <span class="highlight">PersonService</span>);</pre></section><section><h2>Factory</h2><div><span>module.factory(...)</span></div><pre>angular.module('api')
.factory('$person', function ($http) {
<span class="highlight">return {</span>
create: function (info) {
return $http.post('/api/person', info);
}
<span class="highlight">};</span>
});</pre></section><section><h2>Provider</h2><div><span>module.provider(...)</span></div><pre>angular.module('api')
.provider('$person', function () {
<span class="highlight">return {</span>
<span class="highlight">$get:</span> function ($http) {
return {
create: function (info) {
return $http.post('/api/person', info);
}
};
<span class="highlight">}</span>
<span class="highlight">};</span>
});</pre></section><section><h2>Provider</h2><div class="break"></div><ul><li><span>Strong separation between </span><span class="underline">configuration</span><span> and </span><span class="underline">consumption</span></li><li><div>Creates two injectable instances</div><div><pre>$myService, $myServiceProvider</pre></div></li><li><div>Providers can be injected into config callbacks</div><div class="small-85"><pre>// Fail!
angular.module('...')
.config(function ($myService) { ... });
// OK!
angular.module('...')
.config(function ($myServiceProvider) { ... });
angular.module('...')
.run(function ($myService) { ... });
angular.module('...')
.run(function ($myServiceProvider) { ... });</pre></div></li></ul></section><section><h2>Provider</h2><div><span>Example</span></div><div class="small-65"><pre>angular.module('api')
.provider('$person', function () {
var personCache = { };
var provider = { cache: false };
provider.$get = function ($q, http) {
return {
fetch: function (id) {
<span class="highlight">
if (provider.cache && personCache[id]) {
return $q.when(personCache[id]);
}
</span>
return $http.get('/api/persons/' + id)
.then(function (result) {
<span class="highlight">
if (provider.cache) {
personCache[id] = result.data;
}
</span>
return result.data;
});
}
};
};
return provider;
});
angular.module('myApp')
.config(function ($personProvider) {
$personProvider.cache = true;
});</pre></div></section><section><h2>Decorator</h2><div><span>module.decorator(...)</span></div><pre>angular.module('api')
.decorator('$person', function ($delegate) {
var newInstance = {};
// ...
return newInstance;
});</pre><ul><li><span>Use </span><span class="pre">$delegate</span><span> to inject the service</span></li></ul></section><section><h2>Decorator</h2><div><span>Modify a service using decorator</span></div><pre>angular.module('api')
.decorator('$person', function ($q, $delegate) {
var personCache = {};
var fetch = $delegate.fetch;
<span class="highlight">$delegate.fetch = function (id) {
if (personCache[id]) {
return $q.when(personCache[id]);
}
return fetch(id);
};
</span>
return $delegate;
});</pre></section><section><h2>Decorator</h2><div><span>Replace a service using decorator</span></div><pre>angular.module('api')
.decorator('$person', function ($q, $delegate) {
var personCache = {};
<span class="highlight">
return {
fetch: function (id) {
if (personCache[id]) {
return $q.when(personCache[id]);
}
return $delegate.fetch(id);
}
};</span>
});</pre></section></section><section><section><h2>Controllers</h2><div><span>module.controller(...)</span></div><pre>function CreatePersonCtrl($scope, $person) {
$scope.model = {};
$scope.create = function () {
var info = {
FirstName: $scope.model.firstName;
LastName: $scope.model.lastName;
};
$person.create(info)
.then(...);
};
}
angular.module('app')
.controller('CreatePersonCtrl', CreatePersonCtrl);</pre></section></section><section><section><h2><div>Thanks again to our sponsors!</div></h2><h2><div>Thank you for listening!</div></h2><h2 class="break">Questions?</h2></section></section></div></div><script src="lib/js/head.min.js"></script><script src="js/reveal.min.js"></script><script type="text/javascript">// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: true,
theme: Reveal.getQueryHash().theme, // available themes are in /css/theme
transition: Reveal.getQueryHash().transition || 'linear', // default/cube/page/concave/zoom/linear/fade/none
width: 960,
height: 700,
maxScale: 5.0,
rollingLinks: true,
// Optional libraries used to extend on reveal.js
dependencies: [
{ src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: 'plugin/markdown/showdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: 'plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
{ src: 'plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
// { src: 'plugin/search/search.js', async: true, condition: function() { return !!document.body.classList; } }
// { src: 'plugin/remotes/remotes.js', async: true, condition: function() { return !!document.body.classList; } }
]
});</script></body></html>