docs(toh-6): search query fixes

closes #2008
Changes:
- Drop `asObservable()` since it is deprecated in RxJS 5 (see the
[migration
guide](https://github.com/ReactiveX/RxJS/blob/master/MIGRATION.md#operat
ors-renamed-or-removed)).
- Drop `+` from hero search query URL: `app/heroes/?name=${term}+`. At
best it is interpreted as a regex op that serves no purpose, at worst,
it gets interpreted as a space (cf. [HTML 4.01 section
17.13.4](https://www.w3.org/TR/REC-html40/interact/forms.html#h-17.13.4)
).
- Rename `searchSubject` to `searchTerms`
- Other minor tweaks to prose.

This work is in preparation for #1924.

Note: toh-6 tests pass.
This commit is contained in:
Patrice Chalin 2016-08-01 11:22:23 -07:00 committed by Ward Bell
parent 68c9561dec
commit 04d5337b75
4 changed files with 15 additions and 24 deletions

View File

@ -1,13 +1,10 @@
<!-- #docregion --> <!-- #docregion -->
<h3>Top Heroes</h3> <h3>Top Heroes</h3>
<div class="grid grid-pad"> <div class="grid grid-pad">
<!-- #docregion click -->
<div *ngFor="let hero of heroes" (click)="gotoDetail(hero)" class="col-1-4"> <div *ngFor="let hero of heroes" (click)="gotoDetail(hero)" class="col-1-4">
<!-- #enddocregion click -->
<div class="module hero"> <div class="module hero">
<h4>{{hero.name}}</h4> <h4>{{hero.name}}</h4>
</div> </div>
</div> </div>
</div> </div>
<hero-search></hero-search> <hero-search></hero-search>

View File

@ -17,23 +17,22 @@ export class HeroSearchComponent implements OnInit {
// #docregion search // #docregion search
heroes: Observable<Hero[]>; heroes: Observable<Hero[]>;
// #enddocregion search // #enddocregion search
// #docregion searchSubject // #docregion searchTerms
searchSubject = new Subject<string>(); searchTerms = new Subject<string>();
// #enddocregion searchSubject // #enddocregion searchTerms
constructor( constructor(
private heroSearchService: HeroSearchService, private heroSearchService: HeroSearchService,
private router: Router) {} private router: Router) {}
// #docregion searchSubject // #docregion searchTerms
// Push a search term into the observable stream. // Push a search term into the observable stream.
search(term: string) { this.searchSubject.next(term); } search(term: string) { this.searchTerms.next(term); }
// #enddocregion searchSubject // #enddocregion searchTerms
// #docregion search // #docregion search
ngOnInit() { ngOnInit() {
this.heroes = this.searchSubject this.heroes = this.searchTerms
.asObservable() // cast as Observable
.debounceTime(300) // wait for 300ms pause in events .debounceTime(300) // wait for 300ms pause in events
.distinctUntilChanged() // ignore if next search term is same as previous .distinctUntilChanged() // ignore if next search term is same as previous
.switchMap(term => term // switch to new observable each time .switchMap(term => term // switch to new observable each time
@ -41,9 +40,8 @@ export class HeroSearchComponent implements OnInit {
? this.heroSearchService.search(term) ? this.heroSearchService.search(term)
// or the observable of empty heroes if no search term // or the observable of empty heroes if no search term
: Observable.of<Hero[]>([])) : Observable.of<Hero[]>([]))
.catch(error => { .catch(error => {
// Todo: real error handling // TODO: real error handling
console.log(error); console.log(error);
return Observable.of<Hero[]>([]); return Observable.of<Hero[]>([]);
}); });

View File

@ -9,11 +9,9 @@ export class HeroSearchService {
constructor(private http: Http) {} constructor(private http: Http) {}
// #docregion observable-search
search(term: string) { search(term: string) {
return this.http return this.http
.get(`app/heroes/?name=${term}+`) .get(`app/heroes/?name=${term}`)
.map((r: Response) => r.json().data as Hero[]); .map((r: Response) => r.json().data as Hero[]);
} }
// #enddocregion observable-search
} }

View File

@ -419,11 +419,11 @@ block observables-section
Time to create the `HeroSearchComponent` class and metadata. Time to create the `HeroSearchComponent` class and metadata.
+makeExample('toh-6/ts/app/hero-search.component.ts', null,'hero-search.component.ts') +makeExample('toh-6/ts/app/hero-search.component.ts', null,'hero-search.component.ts')
:marked :marked
Focus on the `searchSubject`. Focus on the `searchTerms`.
+makeExample('toh-6/ts/app/hero-search.component.ts', 'searchSubject')(format=".") +makeExample('toh-6/ts/app/hero-search.component.ts', 'searchTerms')(format=".")
:marked :marked
A `Subject` is a producer of an _observable_ event stream. A `Subject` is a producer of an _observable_ event stream.
This `searchSubject` produces an `Observable` of strings, the filter criteria for the name search. This `searchTerms` produces an `Observable` of strings, the filter criteria for the name search.
Each call to `search` puts a new string into this subject's _observable_ stream by calling `next`. Each call to `search` puts a new string into this subject's _observable_ stream by calling `next`.
@ -439,8 +439,6 @@ block observables-section
Fortunately we can chain `Observable` operators to the string `Observable` that reduce the request flow. Fortunately we can chain `Observable` operators to the string `Observable` that reduce the request flow.
We'll make fewer calls to the `HeroSearchService` and still get timely results. Here's how: We'll make fewer calls to the `HeroSearchService` and still get timely results. Here's how:
* The `asObservable` operator casts the `Subject` as an `Observable` of filter strings.
* `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds * `debounceTime(300)` waits until the flow of new string events pauses for 300 milliseconds
before passing along the latest string. We'll never make requests more frequently than 300ms. before passing along the latest string. We'll never make requests more frequently than 300ms.
@ -495,11 +493,11 @@ block observables-section
+makeExample('toh-6/ts/app/app.component.ts', 'rxjs-extensions', 'app/app.component.ts')(format=".") +makeExample('toh-6/ts/app/app.component.ts', 'rxjs-extensions', 'app/app.component.ts')(format=".")
:marked :marked
### Adding the search component to the dashboard ### Add the search component to the dashboard
We add the `HeroSearchComponent` to the bottom of the `DashboardComponent` template. We add the hero search HTML element to the bottom of the `DashboardComponent` template.
+makeExample('toh-6/ts/app/dashboard.component.html', null, 'dashboard.component.html') +makeExample('app/dashboard.component.html')
:marked :marked
And finally, we import the `HeroSearchComponent` and add it to the `directives` array. And finally, we import the `HeroSearchComponent` and add it to the `directives` array.