這次紀錄使用 RxJS 的取得 API 資料欄位,並且完成指定資料的搜尋功能。
畫面架構
有三個輸入框,分別為名稱、性別、地區,並用 form
元件操作,下方為表格,把相對應資料相依渲染在畫面上。
輸入框欄位
main.component.html
formGroup
的屬性繫結裡面可以有許多 input
的內容,只要在每個 input
都加上 formControlName
的指令,並且給予對應的變數,再到 TS 檔建立對應的型別與初始值就可以使用了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| <form [formGroup]="mainForm"> <div class="cardGroup"> <div class="card"> <div class="card-body"> <h5 class="card-title">NAME</h5> <input class="form-control" type="text" placeholder="Enter your name" formControlName="name" /> </div> </div> <div class="card"> <div class="card-body"> <h5 class="card-title">GENDER</h5>
<input class="input" type="radio" id="male" name="gender" value="male" formControlName="gender" /> <label class="inputText" for="male">Male</label>
<input class="input" type="radio" id="female" name="gender" value="female" formControlName="gender" /> <label class="inputText" for="female">Female</label> </div> </div> <div class="card"> <div class="card-body"> <h5 class="card-title">LOCATION</h5> <div class="search"> <input type="text" placeholder="Search name or location" formControlName="location" [(ngModel)]="search" /> <button class="btn btn-warning" (click)="filterData()"> <i class="fas fa-search fa-lg"></i> </button> <button type="button" class="btn btn-success" (click)="submitData()"> 修改 </button> </div> </div> </div> </div> </form>
|
表格 table
main.component.html
- 使用 Bootstrap 的表格元件,快速完成 RWD 與一些表格的互動效果。
- 在
tbody
的 tr
寫上 ngFor
把對應資料用迴圈跑出來。
- 時間使用
date
的水管元件就能輕鬆得到相對應的格式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <div class="table-responsive"> <table class="table table-hover table-bordered"> <thead class="table-indigo"> <tr> <th scope="col">#</th> <th scope="col">NAME</th> <th scope="col">GENDER</th> <th scope="col">LOCATION</th> <th scope="col">TIME</th> <th scope="col">FEATURE</th> </tr> </thead> <tbody> <tr *ngFor="let item of lists"> <td>{{ item.id }}</td> <td>{{ item.name }}</td> <td>{{ item.gender }}</td> <td>{{ item.location }}</td> <td>{{ today | date: "yyyy/MM/dd hh:mm:ss" }}</td> <td class="feature"> <button class="btn btn-secondary" (click)=" editData(item.id, item.name, item.gender, item.location) " > 編輯 </button> <button class="btn btn-danger" (click)="deleteData(item.id)"> 刪除 </button> </td> </tr> </tbody> </table> </div>
|
取得欄位初始值
main.component.ts
因為在 mainForm
裡面有多個欄位,一開始以為是要一個 input
外面就要包一個 formGroup
屬性繫結,結果一直跳錯,後來認真看了錯誤訊息給的提示,才知道是最外面給一個屬性繫結即可。
在參考開發人員工具的範例後,修正如下:
宣告 mainForm
的類別為 FormGroup
的元件,並建立一個 FormGroup
實體,裡面有三個屬性,並給予初始值。
也把會使用到的 id,search,today 等變數給予型別與初始值。
1 2 3 4 5 6 7 8
| mainForm: FormGroup = new FormGroup({ name: new FormControl(), gender: new FormControl(), location: new FormControl(), }); id: number; search: string = ""; today: Date;
|
要用 API 搜尋的 方法
data.service.ts
先到 data
服務元件多建立一個搜尋資料的方法,建立方法前要先做幾件事情。
- 在建構式中建立一個打 API 需要的
options
的內容。
1 2 3 4 5 6 7
| constructor(private http: HttpClient) { this.options = { headers: new HttpHeaders({ 'content-type': 'application/json', }), }; }
|
- 滑鼠移動到其中一個
get
的方法上方時,會跳出一個提示視窗,告訴我以下資訊,
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| headers?: | HttpHeaders | { [header: string]: string | string[]; }; observe?: 'body'; params?: | HttpParams | { [param: string]: string | string[]; }; reportProgress?: boolean; responseType?: 'json'; withCredentials?: boolean;
|
這就是 options
所需要的內容,但這樣太長了,而且可能未來其他頁面要使用這個服務,就把它封裝成 interface
,讓未來需要使用時,只要引入就可以了。
OptionModal.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { HttpHeaders, HttpParams } from "@angular/common/http";
export interface OptionModal { headers?: | HttpHeaders | { [header: string]: string | string[], }; observe?: "body"; params?: | HttpParams | { [param: string]: string | string[], }; reportProgress?: boolean; responseType?: "json"; withCredentials?: boolean; }
|
以上完成後就可以來建立搜尋資料的方法,
data.service.ts
- 建立一個參數,並實體化
HttpParams()
的物件。
- 搜尋方法的參數型別給予之前建立的
interface
內容,也就是欄位帶有 name
、gender
、location
的資料樣式。
- 後續在
append
的方法,把相對的欄位增加出來,讓參數可以對應。
- 再取得 API 的值,看欄位的值是否與資料相符。
- 取得 API 是一個陣列型別的資料樣式,透過
觀察者物件
來確認資料是否回傳為陣列資料的格式。
1 2 3 4 5 6 7 8 9 10
| filterData(filterData: PersonModal): Observable<PersonModal[]> { let params = new HttpParams(); params = params.append('name', filterData.name); params = params.append('gender', filterData.gender); params = params.append('location', filterData.location); return this.http.get<PersonModal[]>(`${this.mainUrl}/posts`, { ...this.options, params, }); }
|
終於要來打 API 囉
- 此時使用剛剛建立好的
filterData
方法,裡面給予屬性,其值就是每個欄位所輸入的值。
- 使用一個變數儲存回傳的值,並確認回傳值是一個陣列。
- 將原本的資料內容替換成新得到的陣列資料,即可完成。
1 2 3 4 5 6 7 8 9 10 11 12 13
| filterData() { return this.dataSvc .filterData({ name: this.mainForm.value.name, gender: this.mainForm.value.gender, location: this.mainForm.value.location, }) .subscribe((res) => { let params: PersonModal[] = res; console.log(params); this.lists = params; }); }
|
完成示意圖