angular11原始碼探索十四[表單校驗器]
阿新 • • 發佈:2021-01-02
自帶的限制條件
Validators.required 報錯 {'required': true} 驗證欄位值是否為true Validators.requiredTrue {required: true} 郵箱 Validators.email {email: true} 最小長度 Validators.minLength(3) {minlength: {requiredLength: 3, actualLength: 2}} 還可以直接在input使用 <input minlength="5"> 最大長度 Validators.maxLength(5) {maxlength: {requiredLength: 5, actualLength: 7} <input maxlength="5"> 正則 Validators.pattern(/foo/) {pattern: {requiredPattern: '^[a-zA-Z ]*$', actualValue: '1'} <input pattern="[a-zA-Z ]*"> 這個頁也可以直接在頁面使用
自定過濾器
//這個傳引數的版本 export function maxLength(maxLength: number): ValidatorFn { return (control: AbstractControl): ValidationErrors|null => { return hasValidLength(control.value) && control.value.length > maxLength ? {'maxlength': {'requiredLength': maxLength, 'actualLength': control.value.length}} : null; }; } 如果不傳引數的話就是這樣的 這個自己編寫的自定義的 export type ValidationErrors = { [key: string]: any }; export function (control: AbstractControl): ValidationErrors|null { return control.value.length > maxLength ? {'maxlength': {'requiredLength': maxLength, 'actualLength': control.value.length}} :null; }; }
這裡可以參考原始碼中的寫法
export interface Validator {
/**
這個是直接的
*/
validate(control: AbstractControl): ValidationErrors|null;
/**
註冊一個回撥函式,當驗證器輸入改變時呼叫, 暫時沒發現用處
*/
registerOnValidatorChange?(fn: () => void): void;
}
管道的自定義指令的時候
@Directive({ selector: '[customValidator]', // 註冊指令,然後頁面使用 providers: [{provide: NG_VALIDATORS, useExisting: CustomValidatorDirective, multi: true}] }) class CustomValidatorDirective implements Validator { validate(control: AbstractControl): ValidationErrors|null { return {'custom': true}; } }
禁用清空錯誤
const arr = new FormArray([new FormControl()], () => ({'expected': true}));
arr.errors // {'expected': true}
arr.disable();
arr.errors // null
arr.enable(); //解除禁用,就繼續報錯
但是當禁用的時候,重新給陣列新增一個FormControl
也促發髒依賴更新,所以也會報錯
FomrBuilder
fbForm: FormGroup;
constructor(
private fb: FormBuilder
) {
this.fbForm = this.fb.group({
firstName: 'some value',
login: ['some',[Validators.required]],
//禁用
should: {value: 'should', disabled: true},
login:fb.control('',{updateOn:'blur'}),
});
this.fbForm = this.fb.group({
firstName: 'some value',
//第三個引數是非同步校驗器
login: ['some', null,[this.asyncValidator1, this.asyncValidator2]],
arrOne: this.fb.array(
['one', 'two'],
null,
[this.asyncValidator1, this.asyncValidator2]
)
}
);
console.log(this.fbForm.get('arrOne')?.errors);
console.log(this.fbForm.get('login')?.errors);
// {'async1': true, 'async2': true}
FormControl 第二個引數配置的幾種形式
如果第一個引數,那麼值主要看value的值,第二個引數還是校驗
const control = new FormControl({ value: 'n/a', disabled: true });
const control = new FormControl('', Validators.required);
const control = new FormControl('', {
validators: Validators.required,// 校驗器
asyncValidators: myAsyncValidator,// 非同步校驗器
updateOn: 'blur'// 校驗方式
});
事件更新
更新策略AbstractControl(表示控制元件自行更新的事件)。
離開的時候,才會觸發校驗
可能的值:'change'| 'blur'| 'submit' 預設值:'change'
我們發現FormGroup, FormControl,FormArray 類似,第二個引數都可以這樣寫
this.fbForm = this.fb.group({
firstName: '',
},{updateOn: 'blur',validators:this.addFn}
);
const a = new FormArray([new FormControl(), new FormControl()], {updateOn: 'blur'});
const control = new FormControl('', { updateOn: 'blur' });
const control = new FormControl('', { updateOn: 'submit' });
====
addFn(control: AbstractControl) {
// 更改了,觸發事件是失去焦點促發
if (control.dirty) {
console.log(control.value);
return {name1: true};
}
}
this.fbForm = this.fb.group({
firstName: ['some value', {
updateOn: 'blur',
validators: [this.addFn]
}],
three:fb.array([
'one','two'
])
})
console.log(this.fbForm.get(['three',1])?.value);// get 還能這樣查
設定校驗
setValidators
const c = new FormControl(null);
//單個值
c.setValidators(Validators.required);
// 多個值
c.setValidators([Validators.minLength(5), Validators.required]);
// 清空校驗器
c.clearValidators();
//設定非同步校驗器
c.setAsyncValidators(asyncValidator('expected'));
//多個非同步校驗器
c.setAsyncValidators([asyncValidator('expected')]);
非同步校驗器
export function asyncValidator(expected: string, timeouts = {}): AsyncValidatorFn {
return (control: AbstractControl) => {
const timeout = (timeouts as any)[control.value] ?? 0;
const result = control.value != expected ? {async: true} : null;
return createValidationPromise(result, timeout);
};
}
function createValidationPromise(
result: ValidationErrors|null, timeout: number): Promise<ValidationErrors|null> {
return new Promise(resolve => {
if (timeout == 0) {
resolve(result);
} else {
setTimeout(() => {
resolve(result);
}, timeout);
}
});
}
使用案例
function asyncFnOne(c:string): AsyncValidatorFn {
return (control: AbstractControl)=> {
console.log(control.value);
return of({name1:true})
}
}
function asyncFnTwo(c:string): AsyncValidatorFn {
return (control: AbstractControl)=> {
console.log(control.value);
return of({name2:true})
}
}
this.profileForm = new FormGroup({
firstName: new FormControl(1, null!, [asyncFnOne('xxx'),asyncFnTwo('bbb')])
});
this.profileForm.get('firstName').asyncValidator(new FormControl(11))
.subscribe(console.log);
// {name1: true, name2: true}