1、案例需求
表單提交,表單全部校驗成功才能提交,當表單校驗錯誤,表單邊框變紅,同時有錯誤提示信息,有重置功能
2、代碼分析
本案例中使用了響應式表單,響應式表單在表單的校驗方面非常方便
2.1、註冊 ReactiveFormsModule
要使用響應式表單,就要從 @angular/forms 包中導入 ReactiveFormsModule 並把它添加到你的 NgModule 的 imports 數組中。
app.module.ts
imports: [
BrowserModule,
AppRoutingModule,
ReactiveFormsModule
]
2.2、使用 FormBuilder 來生成表單控件
當需要與多個表單打交道時,手動創建多個表單控件實例會非常繁瑣。FormBuilder 服務提供了一些便捷方法來生成表單控件。FormBuilder 在幕後也使用同樣的方式來創建和返回這些實例,只是用起來更簡單。
- 注入 FormBuilder 服務
constructor(
private fb: FormBuilder
) { }
- 生成表單控件
FormBuilder 提供了一個語法糖,以簡化 FormControl、FormGroup 或 FormArray 實例的創建過程。它會減少構建複雜表單時所需的樣板代碼的數量(new FormControl)。
this.formGroup = this.fb.group({
name: '',
age: '',
sex: ''
});
2.3、FormGroupDirective
formGroup 是一個輸入指令,它接受一個 formGroup 實例,它會使用這個 formGroup 實例去匹配 FormControl、FormGroup、FormArray 實例,所以模版中的 fromControlName 必須和 formGroup 中的 name 匹配。
<form [formGroup]="formGroup" (ngSubmit)="submit()" novalidate>
<div class="form-group">
<label>姓名:</label>
<input type="text"
formControlName="name">
<p>{{nameErrorMessage}}</p>
</div>
</form>
2.3、表單狀態
每個表單控件都有自己的狀態,共五個狀態屬性,都是布爾值。
- valid 表單值是否有效
- pristine 表單值是否未改變
- dirty 表單值是否已改變
- touched 表單是否已被訪問過
- untouched 表單是否未被訪問過
以輸入姓名的表單爲例,只驗證該表單的必填項時。表單先獲取焦點並且輸入姓名,最後移除焦點,每一步表單的狀態如下:
初始狀態 | |
---|---|
狀態 | 值 |
valid | false |
pristine | true |
dirty | false |
touched | false |
untouched | true |
輸入狀態 | |
---|---|
狀態 | 值 |
valid | true |
pristine | false |
dirty | true |
touched | false |
untouched | true |
失去焦點後狀態 | |
---|---|
狀態 | 值 |
valid | true |
pristine | false |
dirty | true |
touched | true |
untouched | true |
2.4、表單校驗
表單驗證用於驗證用戶的輸入,以確保其完整和正確。Angular內置的了一些校驗器,如 Validators.required, Validators.maxlength,Validators.minlength, Validators.pattern,但是不能自定義錯誤提示信息,所以實用性不強,滿足不了業務場景的需求,於是我們可以自定義表單校驗器。
自定義表單校驗器
name-validator.ts
import { AbstractControl, ValidatorFn } from '@angular/forms';
export function nameValidator(): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } => {
if (!control.value) {
return { message: '請輸入必選項' };
}
if (control.value.length > 10) {
return { message: '名稱大於10位了' };
}
return null;
};
}
使用自定義驗證器
app.component.ts
this.formGroup = this.fb.group({
name: ['', nameValidator()],
age: ['', ageValidator()],
sex: ['', sexValidator()]
});
顯示錯誤提示信息
當頁面初始化的時候不應該顯示錯誤信息,也就是表單touched爲true
// Error
private errorMessage(name): string {
const control = this.formGroup.controls[name];
return (control.touched && control.invalid) ? control.errors.message : '';
}
然而touched只有失去焦點才爲true,在輸入的時候一直爲false。導致在輸入的時候,表單校驗錯誤,卻顯示不了錯誤信息。因此需要再次判斷 dirty 狀態,只要表單值改變,則爲false
private errorMessage(name): string {
const control = this.formGroup.controls[name];
return ((control.touched || control.dirty) && control.invalid) ? control.errors.message : '';
}
2.5、markAsTouched
未對錶單操作時,點擊提交按鈕時,則模擬表單被touched,顯示提示信息
markFormGroupTouched(formGroup: FormGroup) {
Object.values(formGroup.controls).forEach(item => {
if (item.controls) { // 當 formGroup中存在 formGroup 時,遞歸
this.markFormGroupTouched(item.controls);
} else {
item.markAsTouched();
}
});
}