0%

Angular 筆記 - 使用 get API 完成搜尋列表

search

這次紀錄使用 RxJS 的取得 API 資料欄位,並且完成指定資料的搜尋功能。

畫面架構

main

有三個輸入框,分別為名稱、性別、地區,並用 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

  1. 使用 Bootstrap 的表格元件,快速完成 RWD 與一些表格的互動效果。
  2. tbodytr 寫上 ngFor 把對應資料用迴圈跑出來。
  3. 時間使用 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 服務元件多建立一個搜尋資料的方法,建立方法前要先做幾件事情。

  1. 在建構式中建立一個打 API 需要的 options 的內容。
1
2
3
4
5
6
7
constructor(private http: HttpClient) {
this.options = {
headers: new HttpHeaders({
'content-type': 'application/json',
}),
};
}
  1. 滑鼠移動到其中一個 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

  1. 建立一個參數,並實體化 HttpParams() 的物件。
  2. 搜尋方法的參數型別給予之前建立的 interface 內容,也就是欄位帶有 namegenderlocation 的資料樣式。
  3. 後續在 append 的方法,把相對的欄位增加出來,讓參數可以對應。
  4. 再取得 API 的值,看欄位的值是否與資料相符。
  5. 取得 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 囉

  1. 此時使用剛剛建立好的 filterData 方法,裡面給予屬性,其值就是每個欄位所輸入的值。
  2. 使用一個變數儲存回傳的值,並確認回傳值是一個陣列。
  3. 將原本的資料內容替換成新得到的陣列資料,即可完成。
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;
});
}

完成示意圖

filter