1、案例需求
表單提交,表單全部校驗成功才能提交,當表單校驗錯誤,表單邊框變紅,同時有錯誤提示信息,有重置功能
2、名詞解釋
在分析代碼之前,首先明確 FormControl、formControl、formControlName、FormGroup、formGroup、formGroupName、FormArray、formArray、formArrayName 都是什麼意思以及它們的用法。
2.1、FormControl
- FormControl:跟蹤獨立表單控件的值和驗證狀態。它和 FormGroup 和 FormArray 是 Angular 表單的三大基本構造塊之一。它擴展了 AbstractControl 類,並實現了關於訪問值、驗證狀態、用戶交互和事件的大部分基本功能。
當使用響應式表單時,FormControl 類是最基本的構造塊。要註冊單個的表單控件,在組件中導入 FormControl 類,並創建一個 FormControl 的新實例,把它保存在類的某個屬性中。
export class AppComponent implements OnInit {
const control = new FormControl('', Validators.required);
console.log(control.value); // ''
console.log(control.status); // 'INVALID'
}
在組件類中創建了控件之後,還要把它和模板中的一個表單控件關聯起來,爲表單控件添加 formControl 綁定。
<label>
Name:
<input type="text" [formControl]="name">
</label>
- formControl:是一個輸入指令,接受 FormControl 的實例,在模版中使用。
- formControlName: 也是輸入指令,但是它接受的是一個字符串,同 formGroup 指令配合使用。
<div>
<input type="text" [formControl]="myForm.controls.firstName"/>
<input type="text" [formControl]="myForm.controls.lastName"/>
<input type="text" [formControl]="myForm.controls.email"/>
<input type="text" [formControl]="myForm.controls.title"/>
</div>
//等同於
<div [formGroup]="myForm">
<input type="text" formControlName="firstName"/>
<input type="text" formControlName="lastName"/>
<input type="text" formControlName="email"/>
<input type="text" formControlName="title"/>
</div>
FormGroup、FormArray的用法同 FormControl 類似。
3、代碼分析
fromGroup 可以然我們對錶單內容進行分組,方便我們在語義上區分不同類型的輸入,本例中,地址細分爲“省”、“市”、“區”。
this.formGroup = this.fb.group({
name: ['', nameValidator()],
age: ['', ageValidator()],
sex: ['', sexValidator()],
address: this.fb.group({
province: ['', requiredValidator('請輸入省')],
city: ['', requiredValidator('請輸入市')],
district: ['', requiredValidator('請輸入區')]
})
});
address 此時不是 fromControl 而是 formGroup。
<div class="form-group"
formGroupName="address">
<label>地址:</label>
<div>
<label>省:</label>
<input type="text"
formControlName="province">
<p>{{errorMessage('province')}}</p>
</div>
<div>
<label>市:</label>
<input type="text"
formControlName="city">
<p>{{errorMessage('city')}}</p>
</div>
<div>
<label>區:</label>
<input type="text"
formControlName="district">
<p>{{errorMessage('district')}}</p>
</div>
</div>
在獲取 省市區的 formControl 時,可以通過這樣獲取
// 太複雜了
this.formGroup.controls['address'].controls['province'];
// 同樣複雜
this.formGroup.get('address').controls['province'];
// 還好
this.formGroup.get(['address', 'province']);
第三種方式雖然簡單,但是不夠完美,get方法不能一步到位,必須同時傳入 formGroupName 和 formControlName。因此在查看單個表單是否有錯誤信息時,必須先判斷 formControlName 是子組件還是孫子組件。
errorMessage(formControlName: string): string {
let control: AbstractControl;
if (this.formGroup.contains(formControlName)) {
control = this.formGroup.get(formControlName);
} else {
control = this.formGroup.get(['address', formControlName]);
}
return ((control.touched || control.dirty) && control.invalid) ? control.errors.message : '';
}
contains方法:檢查組內是否有一個具有指定名字的已啓用的控件,存在返回 true,不存在返回 false。