---
# System prepended metadata

title: Day31 【牙起來】 Form Getter 與 表單驗證(Validator) - Angular

---

# 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 }
-->
```

