I'm trying to follow the code example in the Angular "Tour-of-Heroes-Tutorial," specifically in the section on setting up an implementation for Search functionality.
My understanding is that the RxJS pipe() function returns a chain of functions that when triggered, will execute. In the case below, the pipe() function is in ngOnInit
(in hero-search.component.ts
) and returns functions that when executed will return Observables. As such, the heroes$
Observable (in hero-search.component.html
and hero-search.component.ts
) will contain functions that when triggered will return Hero(es) Observable(s). What I don't understand is: when exactly will the chained functions in heroes$
be triggered? Put another way, what is the event listener in this case, and where is that listener bound to heroes$
?
What I see is:
1. The Input in hero-search.component.html
is bound to the search()
method in HeroSearchComponent
.
2. The search()
method pushes a new search term into the searchTerms
object (an observable stream).
How exactly does this all find its way to heroes$
and cause the functions in heroes$
to be executed?
Many thanks in advance!
(hero-search.component.ts)
export class HeroSearchComponent implements OnInit {
heroes$: Observable<Hero[]>;
private searchTerms = new Subject<string>();
constructor(private heroService: HeroService) {}
// Push a search term into the observable stream.
search(term: string): void {
this.searchTerms.next(term);
}
ngOnInit(): void {
this.heroes$ = this.searchTerms.pipe(
// wait 300ms after each keystroke before considering the term
debounceTime(300),
// ignore new term if same as previous term
distinctUntilChanged(),
// switch to new search observable each time the term changes
switchMap((term: string) => this.heroService.searchHeroes(term)),
);
}
}
(hero-search.component.html)
<div id="search-component">
<h4>Hero Search</h4>
<input #searchBox id="search-box" (input)="search(searchBox.value)" />
<ul class="search-result">
<li *ngFor="let hero of heroes$ | async" >
<a routerLink="/detail/{{hero.id}}">
{{hero.name}}
</a>
</li>
</ul>
</div>
(from hero.service.ts)
searchHeroes(term: string): Observable<Hero[]>{
if (!term.trim()) {
return of([]);
}
return this.http.get<Hero[]>(`${this.heroesUrl}/?name=${term}`).pipe(
tap(_ => this.log(`found heroes matching "${term}"`)),
catchError(this.handleError<Hero[]>('searchHeroes',[]))
);
}
}