@@ -13,7 +13,7 @@ include ../_util-fns
13
13
It also makes it easier to unit test the component with a mock service.
14
14
15
15
Because data services are invariably asynchronous,
16
- we'll finish the chapter with a promise -based version of the data service.
16
+ we'll finish the chapter with a **!{_Promise}** -based version of the data service.
17
17
18
18
p Run the #[ + liveExampleLink2('' , 'toh-4' )] for this part.
19
19
@@ -64,20 +64,20 @@ code-example(language="bash").
64
64
First, defining heroes is not the component's job.
65
65
Second, we can't easily share that list of heroes with other components and views.
66
66
67
- We can refactor this hero data acquisition business to a single service that provides heroes and
67
+ We can refactor this hero data acquisition business to a single service that provides heroes, and
68
68
share that service with all components that need heroes.
69
69
70
70
### Create the HeroService
71
71
Create a file in the `app` folder called `hero.service.ts`.
72
72
.l-sub-section
73
73
:marked
74
74
We've adopted a convention in which we spell the name of a service in lowercase followed by `.service`.
75
- If the service name were multi-word, we'd spell the base filename with lower dash case (AKA "kebab -case" ).
75
+ If the service name were multi-word, we'd spell the base filename in lower [ dash- case](../guide/glossary.html#!#dash -case).
76
76
The `SpecialSuperHeroService` would be defined in the `special-super-hero.service.ts` file.
77
77
:marked
78
78
We name the class `HeroService` and export it for others to import.
79
79
80
- + makeExample('toh-4/ts/app/hero.service.1.ts' , 'empty-class' , 'hero.service.ts (exported class )' )( format ="." )
80
+ + makeExample('toh-4/ts/app/hero.service.1.ts' , 'empty-class' , 'app/ hero.service.ts (starting point )' )( format ="." )
81
81
82
82
:marked
83
83
### Injectable Services
@@ -96,7 +96,7 @@ code-example(language="bash").
96
96
:marked
97
97
### Getting Heroes
98
98
Add a `getHeroes` method stub.
99
- + makeExample('toh-4/ts/app/hero.service.1.ts' , 'getHeroes-stub' , 'hero.service.ts ( getHeroes stub)' )( format ="." )
99
+ + makeExample('toh-4/ts/app/hero.service.1.ts' , 'getHeroes-stub' , 'app/ hero.service.ts (getHeroes stub)' )( format ="." )
100
100
:marked
101
101
We're holding back on the implementation for a moment to make an important point.
102
102
@@ -117,30 +117,30 @@ code-example(language="bash").
117
117
Cut the `HEROES` array from `app.component.ts` and paste it to a new file in the `app` folder named `mock-heroes.ts`.
118
118
We copy the `import {Hero} ...` statement as well because the heroes array uses the `Hero` class.
119
119
120
- + makeExample('toh-4/ts/app/mock-heroes.ts' , null , 'mock-heroes.ts (Heroes array) ' )
120
+ + makeExample('toh-4/ts/app/mock-heroes.ts' , null , 'app/ mock-heroes.ts' )
121
121
:marked
122
122
We export the `HEROES` constant so we can import it elsewhere — such as our `HeroService`.
123
123
124
124
Meanwhile, back in `app.component.ts` where we cut away the `HEROES` array,
125
125
we leave behind an uninitialized `heroes` property:
126
- + makeExample('toh-4/ts/app/app.component.1.ts' , 'heroes-prop' , 'app.component.ts (heroes property)' )( format ="." )
126
+ + makeExample('toh-4/ts/app/app.component.1.ts' , 'heroes-prop' , 'app/app .component.ts (heroes property)' )( format ="." )
127
127
:marked
128
128
### Return Mocked Heroes
129
129
Back in the `HeroService` we import the mock `HEROES` and return it from the `getHeroes` method.
130
130
Our `HeroService` looks like this:
131
- + makeExample('toh-4/ts/app/hero.service.1.ts' , null , 'hero.service.ts' )( format ="." )
131
+ + makeExample('toh-4/ts/app/hero.service.1.ts' , null , 'app/ hero.service.ts' )( format ="." )
132
132
:marked
133
133
### Use the Hero Service
134
134
We're ready to use the `HeroService` in other components starting with our `AppComponent`.
135
135
136
136
We begin, as usual, by importing the thing we want to use, the `HeroService`.
137
- + makeExample ('toh-4/ts/app/app.component.ts' , 'hero-service-import' , 'app.component.ts (import HeroService) ' )
137
+ + makeExcerpt ('toh-4/ts/app/app.component.ts' , 'hero-service-import' )
138
138
:marked
139
139
Importing the service allows us to *reference* it in our code.
140
140
How should the `AppComponent` acquire a runtime concrete `HeroService` instance?
141
141
142
142
### Do we *new* the *HeroService*? No way!
143
- We could create a new instance of the `HeroService` with " new" like this:
143
+ We could create a new instance of the `HeroService` with ` new` like this:
144
144
+ makeExample('toh-4/ts/app/app.component.1.ts' , 'new-service' )( format ="." )
145
145
:marked
146
146
That's a bad idea for several reasons including
@@ -150,7 +150,7 @@ code-example(language="bash").
150
150
we'll have to find every place we create the service and fix it.
151
151
Running around patching code is error prone and adds to the test burden.
152
152
153
- * We create a new service each time we use " new" .
153
+ * We create a new service each time we use ` new` .
154
154
What if the service should cache heroes and share that cache with others?
155
155
We couldn't do that.
156
156
@@ -168,11 +168,11 @@ code-example(language="bash").
168
168
### Inject the *HeroService*
169
169
170
170
Two lines replace the one line that created with *new*:
171
- 1. we add a constructor.
172
- 1. we add to the component's `providers` metadata
171
+ 1. We add a constructor that also defines a private property .
172
+ 1. We add to the component's `providers` metadata.
173
173
174
174
Here's the constructor:
175
- + makeExample('toh-4/ts/app/app.component.1.ts' , 'ctor' , 'app.component.ts (constructor)' )
175
+ + makeExample('toh-4/ts/app/app.component.1.ts' , 'ctor' , 'app/app .component.ts (constructor)' )
176
176
:marked
177
177
The constructor itself does nothing. The parameter simultaneously
178
178
defines a private `heroService` property and identifies it as a `HeroService` injection site.
@@ -185,14 +185,14 @@ code-example(language="bash").
185
185
:marked
186
186
The *injector* does not know yet how to create a `HeroService`.
187
187
If we ran our code now, Angular would fail with an error:
188
- code-example( format ="." language = "html ") .
188
+ code-example( format ="nocode " ) .
189
189
EXCEPTION: No provider for HeroService! (AppComponent -> HeroService)
190
190
:marked
191
191
We have to teach the *injector* how to make a `HeroService` by registering a `HeroService` **provider**.
192
192
Do that by adding the following `providers` array property to the bottom of the component metadata
193
193
in the `@Component` call.
194
194
195
- + makeExample ('toh-4/ts/app/app.component.1.ts' , 'providers' , 'app.component.ts (providing HeroService) ' )
195
+ + makeExcerpt ('toh-4/ts/app/app.component.1.ts' , 'providers' )
196
196
:marked
197
197
The `providers` array tells Angular to create a fresh instance of the `HeroService` when it creates a new `AppComponent`.
198
198
The `AppComponent` can use that service to get heroes and so can every child component of its component tree.
@@ -205,7 +205,7 @@ a#child-component
205
205
+ makeExample('toh-4/ts/app/app.component.1.ts' , 'get-heroes' )( format ="." )
206
206
:marked
207
207
We don't really need a dedicated method to wrap one line. We write it anyway:
208
- + makeExample ('toh-4/ts/app/app.component.1.ts' , 'getHeroes' , 'app.component.ts (getHeroes)' ) ( format = "." )
208
+ + makeExcerpt ('toh-4/ts/app/app.component.1.ts' , 'getHeroes' )
209
209
210
210
<a id =" oninit" ></a >
211
211
:marked
@@ -232,18 +232,19 @@ a#child-component
232
232
Learn more about lifecycle hooks in the [Lifecycle Hooks](../guide/lifecycle-hooks.html) chapter.
233
233
:marked
234
234
Here's the essential outline for the `OnInit` interface:
235
- + makeExample('toh-4/ts/app/app.component.1.ts' , 'on-init' , 'app.component.ts (OnInit protocol )' )( format ="." )
235
+ + makeExample('toh-4/ts/app/app.component.1.ts' , 'on-init' , 'app/app .component.ts (ngOnInit stub )' )( format ="." )
236
236
:marked
237
237
We write an `ngOnInit` method with our initialization logic inside and leave it to Angular to call it
238
238
at the right time. In our case, we initialize by calling `getHeroes`.
239
- + makeExample ('toh-4/ts/app/app.component.1.ts' , 'ng-on-init' , 'app.component.ts (OnInit protocol)' ) ( format = "." )
239
+ + makeExcerpt ('toh-4/ts/app/app.component.1.ts' , 'ng-on-init' )
240
240
:marked
241
241
Our application should be running as expected, showing a list of heroes and a hero detail view
242
242
when we click on a hero name.
243
243
244
244
We're getting closer. But something isn't quite right.
245
245
246
- ## Async Services and Promises
246
+ <a id="async"></a>
247
+ ## Async Services and !{_Promise}s
247
248
Our `HeroService` returns a list of mock heroes immediately.
248
249
Its `getHeroes` signature is synchronous
249
250
+ makeExample('toh-4/ts/app/app.component.1.ts' , 'get-heroes' )( format ="." )
@@ -257,34 +258,34 @@ a#child-component
257
258
258
259
We'll have to use some kind of asynchronous technique and that will change the signature of our `getHeroes` method.
259
260
260
- We'll use *promises *.
261
+ We'll use *!{_Promise}s *.
261
262
262
- ### The Hero Service makes a promise
263
+ ### The Hero Service makes a !{_Promise}
263
264
264
- A **promise ** is ... well it's a promise to call us back later when the results are ready.
265
+ A **!{_Promise} ** is ... well it's a promise to call us back later when the results are ready.
265
266
We ask an asynchronous service to do some work and give it a callback function.
266
267
It does that work (somewhere) and eventually it calls our function with the results of the work or an error.
267
268
.l-sub-section
268
269
:marked
269
270
We are simplifying. Learn about ES2015 Promises [here](http://exploringjs.com/es6/ch_promises.html) and elsewhere on the web.
270
271
:marked
271
- Update the `HeroService` with this promise -returning `getHeroes` method:
272
- + makeExample('toh-4/ts/app/hero.service.ts' , 'get-heroes' , 'hero.service.ts (getHeroes )' )( format ="." )
272
+ Update the `HeroService` with this !{_Promise} -returning `getHeroes` method:
273
+ + makeExample('toh-4/ts/app/hero.service.ts' , 'get-heroes' , 'app/ hero.service.ts (excerpt )' )( format ="." )
273
274
:marked
274
275
We're still mocking the data. We're simulating the behavior of an ultra-fast, zero-latency server,
275
- by returning an **immediately resolved promise ** with our mock heroes as the result.
276
+ by returning an **immediately resolved !{_Promise} ** with our mock heroes as the result.
276
277
277
- ### Act on the Promise
278
+ ### Act on the !{_Promise}
278
279
Returning to the `AppComponent` and its `getHeroes` method, we see that it still looks like this:
279
- + makeExample('toh-4/ts/app/app.component.1.ts' , 'getHeroes' , 'app.component.ts (getHeroes - old)' )( format ="." )
280
+ + makeExample('toh-4/ts/app/app.component.1.ts' , 'getHeroes' , 'app/app .component.ts (getHeroes - old)' )( format ="." )
280
281
:marked
281
- As a result of our change to `HeroService`, we're now setting `this.heroes` to a promise rather than an array of heroes.
282
+ As a result of our change to `HeroService`, we're now setting `this.heroes` to a !{_Promise} rather than an array of heroes.
282
283
283
- We have to change our implementation to *act on the promise when it resolves*.
284
- When the promise resolves successfully, *then* we will have heroes to display.
284
+ We have to change our implementation to *act on the !{_Promise} when it resolves*.
285
+ When the !{_Promise} resolves successfully, *then* we will have heroes to display.
285
286
286
- We pass our callback function as an argument to the promise 's **then** method:
287
- + makeExample('toh-4/ts/app/app.component.ts' , 'get-heroes' , 'app.component.ts (getHeroes - revised)' )( format ="." )
287
+ We pass our callback function as an argument to the !{_Promise} 's **then** method:
288
+ + makeExample('toh-4/ts/app/app.component.ts' , 'get-heroes' , 'app/app .component.ts (getHeroes - revised)' )( format ="." )
288
289
.l-sub-section
289
290
:marked
290
291
The [ES2015 arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
@@ -316,6 +317,8 @@ a#child-component
316
317
.file typings ...
317
318
.file index.html
318
319
.file package.json
320
+ .file styles.css
321
+ .file systemjs.config.js
319
322
.file tsconfig.json
320
323
.file typings.json
321
324
:marked
@@ -334,11 +337,11 @@ a#child-component
334
337
## The Road We’ve Travelled
335
338
Let’s take stock of what we’ve built.
336
339
337
- * We created a service class that can be shared by many components
338
- * We used the `ngOnInit` Lifecycle Hook to get our heroes when our `AppComponent` activates
339
- * We defined our `HeroService` as a provider for our `AppComponent`
340
- * We created mock hero data and imported them into our service
341
- * We designed our service to return a promise and our component to get our data from the promise
340
+ * We created a service class that can be shared by many components.
341
+ * We used the `ngOnInit` Lifecycle Hook to get our heroes when our `AppComponent` activates.
342
+ * We defined our `HeroService` as a provider for our `AppComponent`.
343
+ * We created mock hero data and imported them into our service.
344
+ * We designed our service to return a !{_Promise} and our component to get our data from the !{_Promise}.
342
345
343
346
p Run the #[ + liveExampleLink2('' , 'toh-4' )] for this part.
344
347
:marked
@@ -357,10 +360,10 @@ p Run the #[+liveExampleLink2('', 'toh-4')] for this part.
357
360
We can simulate a slow connection.
358
361
359
362
Import the `Hero` symbol and add the following `getHeroesSlowly` method to the `HeroService`
360
- + makeExample('toh-4/ts/app/hero.service.ts' , 'get-heroes-slowly' , 'hero.service.ts (getHeroesSlowly)' )( format ="." )
363
+ + makeExample('toh-4/ts/app/hero.service.ts' , 'get-heroes-slowly' , 'app/ hero.service.ts (getHeroesSlowly)' )( format ="." )
361
364
:marked
362
- Like `getHeroes`, it also returns a promise .
363
- But this promise waits 2 seconds before resolving the promise with mock heroes.
365
+ Like `getHeroes`, it also returns a !{_Promise} .
366
+ But this !{_Promise} waits 2 seconds before resolving the !{_Promise} with mock heroes.
364
367
365
368
Back in the `AppComponent`, replace `heroService.getHeroes` with `heroService.getHeroesSlowly`
366
369
and see how the app behaves.
0 commit comments