---
# System prepended metadata

title: 多奇 2020 年 2 月新人職前培訓班 - 4
tags: [Training, Course]

---

# 多奇 2020 年 2 月新人職前培訓班 - 4
###### tags: `Training` `Course`
### Template Driven Form 練習
請至此 [連結](https://github.com/changda0616/doggy-training-template-driven-form)，閱讀 `READMD` 需求完成練習


---

## 介紹

### Model-driven Form
1. 又稱 Reactive Forms
2. 三大組成要素
    1. `FormGroup`
    2. `FormControl`
    3. `FormArray` -> 適用動態新增的欄位
3. 不再使用 `ngModel`, 不再需要 `name` 屬性


### Reactive Forms 中的重要類別
- AbstractControl - 為 Reactive Forms 架構中三個表單類別共同的抽象基底類別(abstract bass class)
- FormControl - 追蹤某一個表單控制項的欄位值與驗證狀態
- FormGroup
    - 追蹤一群表單控制項的欄位值與驗證狀態
    - 以「物件」的方式進行群組 ( 欄位之間沒有順序性，索引值為字串 )

- FormArray - 追蹤一群表單控制項的欄位值與驗證狀態
    - 追蹤一群表單控制項的欄位值與驗證狀態
    - 該群組會以「陣列」的方式進行群組 ( 欄位之間的索引值為數值 )


![](https://i.imgur.com/EMo8Meg.png)

## [實作](https://github.com/changda0616/doggy-training-reactive-form)

### 表單建立方式（2 種）

1. 使用 FormBuilder (較為簡潔)
2. 直接使用 FormControl, FormGroup, FormArray 建立表單元件

#### FormBuilder
```javascript=1
this.form = this.fb.group({
  step1: this.fb.group({
    name: ['', Validators.required],
    phone: ['', [Validators.required, Validators.minLength(7)]]
  }),
  step2: this.fb.group({
    recommandationNumber: ['', Validators.required],
    recommandation: [{ value: '', disabled: true }, Validators.required]
  })
});
```


#### 直接使用 FormControl, FormGroup, FormArray

```javascript=1
this.form = new FormGroup({
  step1: new FormGroup({
    name: new FormControl(['', Validators.required]),
    phone: new FormControl('', [Validators.required, Validators.minLength(7)])
  }),
  step2: new FormGroup({
    recommandationNumber: new FormControl(['', Validators.required]),
    recommandation: new FormControl([{ value: '', disabled: true }, Validators.required])
  })
});

```

### 更新表單內容（3 種） - setValue vs patchValue vs reset

#### setValue - 傳入的資料結構需與 FormGroup 中的物件相同, 屬性找不到會出錯

```javascript=1
this.step1.setValue({
     name:  '',
     phone: ''
});
```

#### patchValue - 僅更新部分屬性，若傳入找不到的屬性，自動忽略

```javascript=1
this.step1.patchValue({
     name:  '',
     mobile: ''
});
```

#### reset - 重置表單內容

1. 清空表單狀態 - 轉為 pristine, untouched
2. 清空欄位內容 - 欄位值變成 null

```javascript=1
this.form.reset();
```

3. 重置為預設內容，若傳入找不到的屬性，自動忽略

```javascript=1
this.form.reset({
    step1: {
        name: '',
        phone: ''
    } 
});
```


---

## 如何選擇
- Template-Driven Forms
    - 宣告式，較為簡單
    - 適合固定數量的表單
    - 無法針對表單進行單元測試，僅能進行 E2E 測試

- Model-Driven Forms
    - 編成式，較為繁瑣
    - 適合動態欄位數量的表單
        - 後台定義的動態問卷、變動選項的投票系統
    - 可以針對表單進行單元測試