iT邦幫忙

2021 iThome 鐵人賽

DAY 12
0
Modern Web

新新新手閱讀 Angular 文件30天系列 第 12

新新新手閱讀 Angular 文件 - Get data from a server(3) - Day12

  • 分享至 

  • xImage
  •  

學習目標

本篇內容為閱讀官方文件 Get data from a server 的筆記內容。
接續 Day11 的內容。

搜尋英雄的資訊

這個小節為在某個搜尋欄位輸入欲搜尋內容後,程式會將我們輸入的內容打出 HTTP 並夾帶給伺服器端,最後,將相關的搜尋內容送回來給我們,並呈現在畫面上。
step 1.
先在 hero.service.ts 檔案中,定義一個 http.get 去向伺服器要資料的 HTTP 操作。

--- hero.service.ts ---
searchHeroes(term: string): Observable<HERO[]> {
    if (!term.trim()) {
      return of([]);
    }
    return this.http.get<HERO[]>(`${this.heroesUrl}/?name=${term}`).pipe(
      catchError(this.handleError<HERO[]>('searchHeroes', []))
    );
}

以上的內容,就是先去防止輸入的查詢內容是空白的,最後,把查詢內容丟到 http.get 中去查詢,查詢成功後,就會回傳以 Hero 作為資料型別的 Observable 的陣列。

step 2.
接著,新增 hero-search 元件到專案中。
所以,輸入指令 ng g c hero-search ,來創出 HeroSearch 元件。
要特別注意的地方是,官方文件中提供的有關 hero-search 元件的 html 的內容,有下列這一段

<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>

以上這個 ul 元素其實是一個 dropdown menu,將搜尋的結果呈現在這個 menu 上。
在 li 中,利用 *ngFor 來遍歷的元素是 heroes$,在後面加一個錢字號 $ ,是要特別聲明它是一個 Observable 的實例,不是一個單純的陣列。

asyncPipe

另外,我們在 heroes$ 後面接了一個 async,它其實叫做 asyncPipe,它是專門用來監聽一個 Observable 實例是否有變化,並透過 subsrcibe 將該 Observable 實例的最新值傳遞出來,也因為它將 Observable 的值傳遞出來,讓 *ngFor 可以去遍歷它傳遞出來的內容。

HeroSearch 元件的內容

接著,我們就要將尋找的相關英雄內容的功能加到 hero-search 元件中了。

import { Component, OnInit } from '@angular/core';
import { HERO } from '../hero'
import { HeroService } from '../hero.service'
import { Subject, Observable } from 'rxjs'
import {
  debounceTime, distinctUntilChanged, switchMap
} from 'rxjs/operators';
@Component({
  selector: 'app-hero-search',
  templateUrl: './hero-search.component.html',
  styleUrls: ['./hero-search.component.css']
})
export class HeroSearchComponent implements OnInit {
  heroes$!: Observable<HERO[]>;
  private searchTerms = new Subject<string>();

  constructor(private heroService:HeroService) {
  }

  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)),
    );
  }
}

可以看到 searchTerms 這個變數是 Subject 的實例。
當觸發 seatrch 函式的時候,會傳入搜尋的英雄名稱,接著,在使用 Subject 的 next 方法來呼叫它,並把英雄名稱傳入,接著,就會進到我們在 ngOnInit 定義的 this.searchTerms.pipe 後面一連串的內容,而在 switchMap 這個 operator 的參數 term 就是我們傳入的英雄搜尋名稱,最後,再把它丟到 searchHeroes 裡面。最終,回傳的資料就會存到 this.heroes$ 裡面囉。

RxJS operators

在以上的程式碼中引入了好幾個來自 rxjs/operators 的模組,分別是 debounceTime, distinctUntilChangedswitchMap,會引入它們的原因是因為,要防止當使用者輸入搜尋內容的時候,會連續觸發 searchHeroes 的事件的狀況產生。
debounceTime(300): 當使用者超過 300 ms 不再輸入之後,就會通過 debounceTime(300) 這關了

distinctUntilChanged : 若舊值和新值不同的時候,才會通過 distinctUntilChanged 這關

switchMap : 它會拋棄之前舊的回傳值,並接收由最新發出的 HTTP 請求所回傳的最新的回傳值。

加到 dashboard 中

最後,我們將 heroSearch 元件加到 dashBoard 裡面。

<h2>Top Heroes</h2>
<div class="heroes-menu">
  <a *ngFor="let hero of heroes" (click)="goDetail(hero.id)">
    {{ hero.name }}
  </a>
</div>

<app-hero-search></app-hero-search>

最終成果

Summary

這邊做個總結

  1. 如何使用 asyncPipe 來將 Observable 型別的資料內容傳送出來,讓 *ngFor 可以遍歷它。
  2. 如何搭配使用 subject 並搭配 debounceTime, switchMap,來完成一個 auto-complete 的功能。

上一篇
新新新手閱讀 Angular 文件 - Get data from a server(2) - Day11
下一篇
新新新手閱讀 Angular 文件 - Interpolation(1) - Day13
系列文
新新新手閱讀 Angular 文件30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言