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