@@ -131,7 +131,7 @@ block get-heroes-details
131
131
:marked
132
132
The Angular `http.get` returns an RxJS `Observable`.
133
133
*Observables* are a powerful way to manage asynchronous data flows.
134
- We'll learn about ` Observables` * later* .
134
+ We'll learn about [ Observables](#observables) later in this chapter .
135
135
136
136
For *now* we get back on familiar ground by immediately converting that `Observable` to a `Promise` using the `toPromise` operator.
137
137
+ makeExample('toh-6/ts/app/hero.service.ts' , 'to-promise' )( format ="." )
@@ -361,41 +361,69 @@ block review
361
361
:marked
362
362
## Observables
363
363
364
- In this section we discuss `Observables` as an alternative to promises when processing http calls .
364
+ Each `Http` method returns an `Observable` of HTTP `Response` objects .
365
365
366
- `Http` calls return RxJS observables by default, but so far we've been hiding that by converting the observable to a promise by calling `toPromise`.
366
+ Our `HeroService` converts that `Observable` into a `Promise` and returns the promise to the caller.
367
+ In this section we learn to return the `Observable` directly and discuss when and why that might be
368
+ a good thing to do.
367
369
368
- Observables and promises are both great for processing http calls, but as we will see, the observables api is much richer.
370
+ ### Background
371
+ An *observable* is a stream of events that we can process with array-like operators.
369
372
370
- `RxJs` offers a wide variety of operators that we can use to manage event flows.
373
+ Angular core has basic support for observables. We developers augment that support with
374
+ operators and extensions from the [RxJS Observables](http://reactivex.io/rxjs/) library.
375
+ We'll see how shortly.
371
376
372
- In this section we will discuss how to use some of these operators to build a type-to-search filter where we can search for heroes by name.
377
+ Recall that our `HeroService` quickly chained the `toPromise` operator to the `Observable` result of `http.get`.
378
+ That operator converted the `Observable` into a `Promise` and we passed that promise back to the caller.
379
+
380
+ Converting to a promise is often a good choice. We typically ask `http` to fetch a single chunk of data.
381
+ When we receive the data, we're done.
382
+ A single result in the form of a promise is easy for the calling component to consume
383
+ and it helps that promises are widely understood by JavaScript programmers.
384
+
385
+ But requests aren't always "one and done". We may start one request,
386
+ then cancel it, and make a different request ... before the server has responded to the first request.
387
+ Such a _request-cancel-new-request_ sequence is difficult to implement with *promises*.
388
+ It's easy with *observables* as we'll see.
389
+
390
+ ### Search-by-name example
391
+ We're going to add a *hero search* feature to the Tour of Heroes.
392
+ As the user types a name into a search box, we'll make repeated http requests for heroes filtered by that name.
373
393
374
- We start by creating `HeroSearchService`, a simple service for sending search queries to our api.
394
+ We start by creating `HeroSearchService` that sends search queries to our server's web api.
375
395
376
396
+ makeExample('toh-6/ts/app/hero-search.service.ts' , null , 'app/hero-search.service.ts' )( format ="." )
377
397
378
398
:marked
379
- The http call in `HeroSearchService` is not that different from our previous http calls, but we no longer call `toPromise`. This means we will return an observable instead of a promise.
399
+ The `http.get` call in `HeroSearchService` is similar to the `http.get` call in the `HeroService`.
400
+ The notable difference: we no longer call `toPromise`.
401
+ We simply return the *observable* instead.
380
402
381
- Now, let's implement our search component `HeroSearchComponent`.
382
-
383
- + makeTabs(
384
- ` toh-6/ts/app/hero-search.component.ts,
385
- toh-6/ts/app/hero-search.component.html` ,
386
- null ,
387
- ` hero-search.component.ts,
388
- hero-search.component.html`
389
- )
403
+ ### HeroSearchComponent
404
+ Let's create a new `HeroSearchComponent` that calls this new `HeroSearchService`.
390
405
406
+ The component template is simple - just a textbox and a list of matching search results.
407
+ + makeExample('toh-6/ts/app/hero-search.component.html' , null ,'hero-search.component.html' )
391
408
:marked
392
- The `HeroSearchComponent` UI is simple - just a textbox and a list of matching search results.
393
-
394
- To keep track of text changes in the search box we are using an RxJs `Subject`.
409
+ As the user types in the search box, a *keyup* event binding calls `search.next` with the new search box value.
395
410
396
- Observables are great for managing event streams. In our example we will actually be dealing with two different types of event streams:
411
+ The componen'ts data bound `search` property returns a `Subject`.
412
+ A `Subject` is a producer of an _observable_ event stream.
413
+ Each call to `search.next` puts a new string into this subject's _observable_ stream.
414
+
415
+ Create a `HeroSearchComponent` as follows.
416
+ + makeExample('toh-6/ts/app/hero-search.component.ts' , null ,'hero-search.component.ts' )
417
+ :marked
418
+ Scroll down to where we create the `search` subject.
419
+ + makeExample('toh-6/ts/app/hero-search.component.ts' , 'subject' )
420
+ :marked
421
+ We're binding to that `search` subject in our template.
422
+ The user is sending it a stream of strings, the filter criteria for the name search.
397
423
398
- 1) Key events from typing into the search textbox
424
+ A `Subject` is also an `Observable`.
425
+ We're going to access that `Observable` and add operators to that turn the stream
426
+ of filter strings into a stream of http search results.
399
427
400
428
2) Results from http calls based on values entered in the search textbox
401
429
@@ -539,4 +567,4 @@ block file-summary
539
567
hero-search.component.ts,
540
568
hero-search.service.html,
541
569
rxjs-operators.ts`
542
- )
570
+ )
0 commit comments