angular11源码探索十四[表单校验器]

自带的限制条件

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}
posted @ 2021-01-02 10:47  猫神甜辣酱  阅读(239)  评论(0编辑  收藏  举报