# Day31 【牙起來】 Form Getter 與 表單驗證(Validator) - Angular
## 驗證器
驗證器只是一個狀態的`True`或`False`表達式
如果要達成以下這些功能,都要**自己額外寫邏輯**
* 輸入錯誤出現紅色框框
* 沒全部輸入完畢不能按送出
使用驗證器的`True`、`False`結果來實現這些事情
以下的驗證器,一個驗證器都對應一個測試項目的真假
## 單一個表單驗證器
只對輸入框綁定一個驗證器
把`name`這一項變成**必填**欄位,沒填的話驗證器為`invalid`
修改`user-input.component.ts`
```typescript=
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
...
export class UserInputComponent implements OnInit {
myForm: FormGroup;
constructor(private fb: FormBuilder) {
this.myForm = fb.group({
name: ['勇者一號', Validators.required],
age: 19,
});
}
...
```
## 多個表單驗證器
對同一個輸入框綁定多個驗證器
現在`age`這一項必須同時滿足**必填**、**最大值**、**最小值**,此欄位的狀態才會為`valid`,否則為`invalid`
修改`user-input.component.ts`
```typescript=
...
export class UserInputComponent implements OnInit {
myForm: FormGroup;
constructor(private fb: FormBuilder) {
this.myForm = fb.group({
name: ['勇者一號', Validators.required],
age: [25, [Validators.required, Validators.min(5), Validators.max(120)]],
});
}
...
```
## 在樣板上呈現效果
用`FormGroup.get('')`取出對應FornControlName的欄位控制器,再取得底下的`valid`或`invalid`
> 因為`FormGroup.get('')`[有可能取到`null`](https://stackoverflow.com/questions/65966720/error-ts2531-object-is-possibly-null-in-angular-reactive-forms),所以要加上問號`?`
修改`user-input.component.html`
```html=
<form [formGroup]="myForm">
<div>名稱:<input type="text" formControlName="name" [ngClass]="{'bg-danger': myForm.get('name')?.invalid}"></div>
<div>年紀:<input type="text" formControlName="age" [ngClass]="{'bg-danger': myForm.get('age')?.invalid}"></div>
</form>
```
可以直接把驗證器結果 `valid`、`invalid` 印出來樣板上看看
可在`user-input.component.html`添加
```html=
========
{{myForm.get('name')?.valid}}
{{myForm.get('name')?.invalid}}
```
### Getter
或者也可以這樣做
在程式端加上`Getter` 返回FornControlName的欄位控制器
使用Getter時直接取得
修改`user-input.component.ts`
```typescript=
...
export class UserInputComponent implements OnInit {
myForm: FormGroup;
get Age() { return this.myForm.get('age'); }
get Name() { return this.myForm.get('name'); }
constructor(private fb: FormBuilder) {
this.myForm = fb.group({
name: ['勇者一號', Validators.required],
age: [25, [Validators.required, Validators.min(5), Validators.max(120)]],
});
}
...
```
接著在樣板上直接取`Age`、`Name`即可
修改`user-input.component.html`
```html=
<form [formGroup]="myForm">
<div>名稱:<input type="text" formControlName="name" [ngClass]="{'bg-danger': Name?.invalid}"></div>
<div>年紀:<input type="text" formControlName="age" [ngClass]="{'bg-danger': Age?.invalid}"></div>
</form>
```
---
> 我要吐了
> 我只是想達到"如果輸入值超過上限的話自動把值設為最大值"
> 為什麼要加這麼多東西
> 驗證器、Getter、ngClass is-invalid
> 嘔嘔嘔嘔偶
// TODO
目前只提formbuilder的驗證器
還差FormGroup的
```typescript=
export const LanguageForm = new FormGroup({
'en': new FormControl('', [Validators.required, Validators.minLength(6)]), // 最低六碼限制? Validators.minLength(6)
'zh-Hant': new FormControl('', Validators.required),
'zh-Hans': new FormControl('', Validators.required),
'ja': new FormControl(''),
});
```
輸入驗證 擋送出表單
```typescript=
if (this.form.valid) {
console.log('form submitted');
}
```
formControl 預設disable
https://stackoverflow.com/questions/42840136/disable-input-fields-in-reactive-form
巢狀表單
```typescript=
{{form.getRawValue() | json}}
{{form.value | json}}
```
```typescript=
form2 = this.fb.group({
f1: [0, Validators.max(99)],
f2: [{value: 0}, Validators.max(99)],
f3: [{value: 0, disabled: false}, Validators.max(99)],
f4: [{value: 0, disabled: true}, Validators.max(99)],
});
```
兩者差異
[getRawValue、value的坑](https://blog.kevinyang.net/2020/05/06/angular-formgroup-value/)
```html=
{{form2.getRawValue() | json}}
<br>
{{form2.value | json}}
<!--
{ "f1": 0, "f2": { "value": 0 }, "f3": 0, "f4": 0 }
{ "f1": 0, "f2": { "value": 0 }, "f3": 0 }
-->
```