iT邦幫忙

2021 iThome 鐵人賽

DAY 16
1
Modern Web

Angular 深入淺出三十天:表單與測試系列 第 16

Angular 深入淺出三十天:表單與測試 Day16 - Template Driven Forms vs Reactive Forms

Day16

這段期間,我們用 Template Driven FormsReactive Forms 各自做了一個登入表單(靜態)與被保人表單(動態),而且我們也都為這些表單寫了單元測試整合測試,大家應該對於這兩種開發表單的方式有一定的認知與體會。

因此,我們今天來將這兩種開發表單的方式做個小結與比較,順便沉澱一下這段時間的學習成果。

Template Driven Forms vs Reactive Forms

一般我們在對比這兩個開發表單的方式時,會用以下三個面向來分析優劣:

  1. 開發難易度
  2. 維護難易度
  3. 測試難易度

開發難易度

開發難易度指的是,開發者分別使用這兩種開發表單的方式開發同一個表單時的難易程度。

而這段時間,我也讓大家跟著我一起分別使用這兩種開發表單的方式開發了兩個表單,大家可以自己在心裡比較看看。

Template Driven Forms

Template Driven Forms 的方式很接近前端原始寫法,資料的驗證與限制都是使用 HTML 原生的表單機制,只是再額外加上 Angular 的資料綁定機制範本語法來處理,對於剛開始使用框架的初學者較為友善。

就像這樣:

<input
  type="email"
  name="account"
  id="account"
  required
  pattern="\b[\w\.-]+@[\w\.-]+\.\w{2,4}\b"
  #accountNgModel="ngModel"
  [ngModel]="account"
  (ngModelChange)="
    accountValueChange(accountNgModel.value, accountNgModel.errors)
  "
/>

Reactive Forms

Reactive Forms 的方式則是直接用程式來創建與操作表單物件 ─ FormGroup ,然後再把相應的 FormControl 綁定到畫面上的表單欄位。

就像這樣

const data = {
  account: ['', [ /* Validators... */]]
  password: ['', [ /* Validators... */]]
};
const formGroup = this.formBuilder.group(data);
<form [formGroup]="formGroup">
  <input
    type="email"
    id="account"
    formControlName="account"
  />
  <input
    type="password"
    id="password"
    formControlName="password"
  />
</form>

Template Driven Forms 相比,大部分的程式新手會覺得較為抽象,且會有相對來說比較多較困難、較不習慣的觀念要熟悉,學習成本較高

此外,如果有遇到更複雜的連動邏輯、更動態的表單,會比較需要對 RxJS 有更進一步的認知。

開發難易度小結

大部分剛學 Angular 的朋友應該都會覺得 Template Driven Forms 比較簡單,不過雖然一開始做的時候好像很簡單且自然,但表單一複雜起來,那沱 HTML 實在是會有點慘不忍睹。

這還是因為我們這段時間所做的表單其實很陽春、很簡單,如果我們要做的是有著更複雜的連動邏輯、更動態的表單,光想到要處理一堆事情就頭皮發麻、冷汗狂流。

Reactive Forms 初接觸時好像感覺很難,但隨著熟悉度的提升,大家一定會覺得它越來越好用,用它來開發又快又輕鬆,尤其當要做的表單越複雜、越動態時,更能體會它的美好。

我自己一開始使用 Angular 的時候也是只會使用 Template Driven Forms 的開發方式來開發,甚至還實作過頗為複雜的動態表單。直到我學會了使用 Reactive Forms 的開發方式之後,才發現之前做的表單有多麼可怕。

維護難易度

我這邊的維護難易度主要指的是以擴充性重用性這兩種面向來比較這兩種開發方式的難易程度。

Template Driven Forms

擴充性來說,假如我們一起開發過被保人表單需要新增一個產品欄位,並增加年齡與產品之間的互動邏輯時,除了要在 Template 上新增一個產品欄位與其必須的驗證之外,在 Component 裡也需要加上相應欄位有變動時,與其他欄位的互動、提示訊息的邏輯。

重用性來說,假如今天有同樣的表單欄位與驗證邏輯要在別的地方使用,但是畫面可能會長得很不一樣,抑或是只是其他表單裡的其中幾個欄位,這時為了要重用也會需調整不少程式碼。

好一點的情況可能只需要將這些欄位包裝起來並增加 input/output 的邏輯,差一點的情況大概就連重用都很困難,只能盡量把能抽的邏輯抽離,又或者把他們抽成最小最不會有影響的 Component 來使用。

Reactive Forms

擴充性來說,不管是要新增欄位還是調整結構,由於 Reactive Forms 本身就是用程式來建立表單,所以基本上都只需要在程式裡處理好,而 Template 就只是很簡單的增加該增加的欄位、並給予相應的綁定而已,如 formContorlName="xxx" ,輕鬆自在。

重用性來說,這件事在 Reactive Forms 看來更是小菜一碟。本來就是用程式建立表單的它,本身基本就具備非常良好的重用性,就算要把原本的表單抽成最小單位的 FormControl ,也只是像樂高積木一樣,需要的時候再組合起來就好。

維護難易度小結

簡單來說, Template Driven Forms 的開發方式有點像在煮義大利麵,煮完之後就很難去分離,雖然麵依然是麵、醬汁依然是醬汁,但麵已飽富醬汁、醬汁也難以再還原回原本的食材。

Reactive Forms 就像是樂高積木,具有豐富的可變性與卓越的彈性,你想要怎麼組合都可以,就算拼成樂高版的義大利麵,也是說拆就拆、說散就散。

雖然整體來說還是要看個人的功力,但就同一個人用這兩種方法來比較的話,應該還是會有差不多的結果。

測試難易度

測試嚴格來說應該是維護中的一環,因為每當程式碼有調整時,或者是需求有調整時,都有可能會影響到測試。

不過此處特別提出來比較主要是想要只在撰寫測試這件事情上來比較這兩種方式的難易度,尤其是我們這段時間總計寫了八篇的測試,大家應該會比較能感同身受。

Template Driven Forms

Template Driven Forms 在撰寫測試上也因為其方式很接近前端原始寫法的關係,我覺得還算好寫,只要檢查元素的屬性與其值即可。

但由於 Template Driven Forms 比較不可控,且其更新時機是非同步且比較不可預測的關係,造成想要把它的測試寫得很好並不容易。

就拿我們寫過的測試來說,我們在第七天第十三天時,都有著過相同的問題,而這問題,說不定其實是我寫不好,並不是框架本身的問題。

所以說,在某些特定情境下的測試案例,要寫得好其實並不容易。

Reactive Forms

Reactive Forms 的更新時機基本上是同步且可預測的,有什麼變化就可以直接驗證到,畢竟它本身就是用程式來建立表單,可控性很高。

同樣地拿我們寫過的測試來說,相信大家應該都沒有遇到什麼問題,不知道大家是否也覺得它的測試案例相對好寫呢?

測試難易度小結

撰寫測試的難易度其實很大程度地影響了開發人員是否會持續撰寫或維護測試程式的意願。

所以對開發人員來說,當然是越容易越好。

本日小結

今天主要是想明確地讓大家知道 Template Driven FormsReactive Forms 之間的不同與更清楚地對比,讓大家未來在遇到需要製作表單的情境時,可以根據需求來選擇最適合的方式。

下表總結了 Template Driven FormsReactive Forms 的不同之處:

  Reactive Forms Template Driven Forms
表單模型的設置 清楚的,在 Component 裡建立 隱晦的,用 Directive 建立
資料模型 有結構性且不變的 鬆散且容易改變
可預測性 同步的 非同步的
表單驗證方式 用函式驗證 Directive 驗證

雖說這段時間有分享如何使用 Template Driven Forms 的方式來開發表單,不過我個人在遇到要製作表單的情境時,其實都是選擇用 Reactive Forms 的方式來開發,因為實在是真的太好寫了!

此外,我們的後續文章也將不會再分享 Template Driven Forms 的開發方式,而是會用 Reactive Forms 的方式來分享更多更進階的用法,讓大家可以因應更複雜、更動態的情境。

如果你有任何的問題或是回饋,還請麻煩留言給我讓我知道,感謝大家!


上一篇
Angular 深入淺出三十天:表單與測試 Day15 - 整合測試實作 - 被保人 by Reactive Forms
下一篇
Angular 深入淺出三十天:表單與測試 Day17 - E2E 自動化測試工具簡介
系列文
Angular 深入淺出三十天:表單與測試30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言