Angular Material Form field校驗詳解

Angular Material Form field校驗詳解

概述

在Material的官方文檔中,我們可以看到 Form field 組件中提供了錯誤信息提示的封裝,例子如下:


<mat-form-field>

<mat-error>{{getErrorMessage()}}/<mat-error>
/<mat-form-field>

import {Component} from '@angular/core';
import {FormControl, Validators} from '@angular/forms';
/** @title Form field with error messages */
@Component({
selector: 'form-field-error-example',
templateUrl: 'form-field-error-example.html',
styleUrls: ['form-field-error-example.css'],
})
export class FormFieldErrorExample {
email = new FormControl('', [Validators.required, Validators.email]);
getErrorMessage() {
return this.email.hasError('required') ? 'You must enter a value' :
this.email.hasError('email') ? 'Not a valid email' :
'';
}
}

在官方的例子下,我們可以得到如下的效果:


Angular Material Form field校驗詳解


Angular Material Form field校驗詳解


我們可以看到 mat-error 是需要放置到 mat-form-field 內部的。只有放在內部的情況下,才可以實現動畫的效果。

進階

要實現上面的兩種錯誤校驗,需要在FormControl中設置相應的Validators。FormControl支持的校驗方式我們可以歸結為兩種: sync和async。

sync同步校驗

像前面例子中的 Validators.required 和 Validators.email 就是sync同步校驗。同步校驗指的是在用戶數據後就同步的進行校驗,可以實時的對輸入內容進行校驗反饋。

async異步校驗

異步校驗主要應用於與後臺有交互的情景,比如要填寫一個編號,系統要求編號是唯一的,此時我們輸入的值就數據發送到後臺進行校驗,確保當前值系統中不存在。

異步實例:

import {Component} from '@angular/core';
import {FormControl, Validators} from '@angular/forms';
import { HttpClient } from '@angular/common/http';
/** @title Form field with error messages */
@Component({
selector: 'form-field-error-example',
templateUrl: 'form-field-error-example.html',
styleUrls: ['form-field-error-example.css'],
})
export class FormFieldErrorExample {

constructor(private http: HttpClient) {}
email = new FormControl('', [Validators.required, Validators.email], [this.asyncValidator()]);
getErrorMessage() {
return this.email.hasError('required') ? 'You must enter a value' :
this.email.hasError('email') ? 'Not a valid email' :
'';
}


asyncValidator(): AsyncValidatorFn {

return (control: AbstractControl): Promise<validationerrors> | Observable<validationerrors> => {

const email = control.value;

return this.http.get('/validate/' + email).pipe(
map((data) => return data.length > 0 ? {exist: true, msg: 'Duplicate email'} : null;)
);
};
}
}
/<validationerrors>/<validationerrors>

組合異步校驗

基於上面的例子,我們再添加一個手機號的字段,現在我們的需求是手機號+郵箱組合不能重複。那麼我們應該怎麼實現這個異步校驗呢?

可以肯定的是,組合校驗的實現套路和上面的單個字段異步校驗時一樣的,只是需要我們在單個字段異步校驗的基礎上進行相應的擴展。

asyncValidator(phoneCtr: AbstractControl): AsyncValidatorFn {
return (control: AbstractControl): Promise<validationerrors> | Observable<validationerrors> => {
const phone = phoneCtr.value;
const email = control.value;

return this.http.get('/validate/' + email + '/' + phone).pipe(
map((data) => return data.length > 0 ? {exist: true} : null;)
);
};
}
/<validationerrors>/<validationerrors>

這樣我們在聲明Control的時候,也需要進行相應的調整:

export class FormFieldErrorExample {

constructor(private http: HttpClient) {}
phone = new FormControl('');
email = new FormControl('', [Validators.required, Validators.email], [this.asyncValidator(phone)]);
getErrorMessage() {
return this.email.hasError('required') ? 'You must enter a value' :
this.email.hasError('email') ? 'Not a valid email' :
this.email.hasError('exist') ? 'Duplicate email and phone combination'
'';
}

asyncValidator(phoneCtr: AbstractControl): AsyncValidatorFn {
return (control: AbstractControl): Promise<validationerrors> | Observable<validationerrors> => {
const phone = phoneCtr.value;
const email = control.value;

if (!phone || !email) {
return of(null);
}
return this.http.get('/validate/' + email + '/' + phone).pipe(
map((data) => return data.length > 0 ? {exist: true} : null;)
);
};
}
}
/<validationerrors>/<validationerrors>

我們在輸入phone後,再輸入email,會觸發這個異步校驗。此時的異步校驗只有在email的內容變更時才會觸發。

那麼問題又來了,我們可能先輸入email,再輸入phone,該怎麼觸發這個異步校驗呢?

我們可以通過監聽phone的變更然後出通知email去觸發校驗:

this.phone.valueChanges.subscribe(() => {
// this.repaymentTypeControl.markAsTouched();
this.repaymentTypeControl.updateValueAndValidity()
});

結論

在實際開發的過程中,我們要開發各種各樣的校驗,有些校驗規則的實現方式沒有現成的例子,此時就需要我們自己去閱讀框架的源碼,從中找尋那一點點的曙光。


分享到:


相關文章: