0

Could you tell me the advantage in using an Observable for heroes$ in Angular's livesearch tutorial? (https://angular.io/tutorial/toh-pt6)

Or in other words, is there something "wrong" with using a regular object instead of an observable at all in this particular example?

Original example 1 - with Observable:

export class HeroSearchComponent implements OnInit {
  heroes$!: Observable<Hero[]>;
  private searchTerms = new Subject<string>();

  constructor(private heroService: HeroService,
    private http: HttpClient) {}

  search(term: string): void {
    this.searchTerms.next(term);
  }

  ngOnInit(): void {
    this.heroes$ = this.searchTerms.pipe(
      debounceTime(300),
      distinctUntilChanged(),
      switchMap((term: string) => this.heroService.searchHeroes(term)),
    );
  }
  
  searchHeroes(term: string): Observable<Hero[]> {
    if (!term.trim()) {
      return of([]);
    }
    return this.http.get<Hero[]>(`${'api/heroes'}/?name=${term}`)
  }
}
<div id="search-component">
  <label for="search-box">Hero Search</label>
  <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>

Version 2 without Observable:

export class HeroSearchComponent implements OnInit {
  heroes!: Hero[];
  private searchTerms = new Subject<string>();

  constructor(private heroService: HeroService,
    private http: HttpClient) {}

  search(term: string): void {
    this.searchTerms.next(term);
  }

  ngOnInit(): void {
    this.searchTerms.pipe(
      debounceTime(300),
      distinctUntilChanged(),
      switchMap((term: string) => this.heroService.searchHeroes(term)),
    ).subscribe(heroes => this.heroes = heroes);
  }
  
  searchHeroes(term: string): Observable<Hero[]> {
    if (!term.trim()) {
      return of([]);
    }
    return this.http.get<Hero[]>(`${'api/heroes'}/?name=${term}`)
  }
}

<div id="search-component">
  <label for="search-box">Hero Search</label>
  <input #searchBox id="search-box" (input)="search(searchBox.value)" />

  <ul class="search-result">
    <li *ngFor="let hero of heroes" >
      <a routerLink="/detail/{{hero.id}}">
        {{hero.name}}
      </a>
    </li>
  </ul>
</div>

Why would I favor an observable for this livesearch in particular?

Thanks in advance!

  • When you use an observable you should "unsubscribe" (generally you unsubscribe in ngOnDestroy, see, e.g. this [SO](https://stackoverflow.com/questions/38008334/angular-rxjs-when-should-i-unsubscribe-from-subscription) using takeUntil. The [pipe async](https://angular.io/api/common/AsyncPipe), makes the work for you. For me is more "comfortable" using the pipe async aproach, but it's equal valid yours – Eliseo Dec 15 '21 at 19:49
  • You don't need to unsubscribe from http request. It's get value once and unsubscribe automatically. – Anton Marinenko Dec 18 '21 at 07:19

1 Answers1

1

First of all, here you have a request to the server. It works with HttpClient module, and it returns Observable value by default. You can do the same with Promise, but should check Promise vs Observable difference. Angular is all about Observable and RxJS.

For example for that live search an easy reason to use observable is cancellable answer, what's impossible to do with promise. SwitchMap operator do it for you in the right place.

Secondly, it's the view recalculation with ChangeDetectionStrategy. Async pipe do the right job and give you the best performance and easy usage.

Anton Marinenko
  • 2,749
  • 1
  • 10
  • 16