angular11源码探索十三[表单基础篇二]

statusChanges

statusChanges: Observable

每次验证的状态,参数 status

new FormControl({value: '', disabled: true} 禁用也可以这样写

当我们手动设置报错

 const login = new FormControl('someLogin');
      login.setErrors({
        notUnique: true
      });
login.valid //false, 是否通过校验
login.setValue('aaa')
login.valid //true

get查询方式

 profileForm: FormGroup = new FormGroup({
    address: new FormGroup({
      name1: new FormControl()
    })
  });
this.profileForm.get('address.name1');
this.profileForm.get(['address', 'name1']);
两种形式等价

getError/hasError 区别

查找方式

get('xxx')
get('aaa.bbb')
get(['aaa','bbb'])
get(['aaa',0]) // 数字就是索引

hasError 报错查找

    this.profileForm.get(['address','name1'])?.setErrors({aaa:true})// 设置报错
    console.log(this.profileForm.get(['address', 'name1'])?.hasError('aaa'));
		等价
    console.log(this.profileForm?.hasError('aaa', ['address', 'name1']));// true

源码

  getError(errorCode: string, path?: Array<string|number>|string): any {
    const control = path ? this.get(path) : this;
    return control && control.errors ? control.errors[errorCode] : null;
  }

  hasError(errorCode: string, path?: Array<string|number>|string): boolean {
    return !!this.getError(errorCode, path);
  }

却别应该是返回类型不一样吧,而且两者本质上就是父子关系,

上个小案例

 let aa = this.profileForm.get('firstName') as FormControl;
    aa.setErrors({'aaa': '333'});
    console.log(aa.getError('aaa'));// 333
    console.log(aa.hasError('aaa'));// true

addControl 添加

  (this.profileForm.get('address') as FormGroup).addControl('newControl', new FormControl(''));
    this.profileForm.addControl('name1',new FormControl())
    console.log(this.profileForm.value);

removeControl

    this.profileForm.removeControl('address')

当删除或者增加的时候,页面没有生效,其实应该在OnInit 生命周期中添加

ngModel双向绑定

<input type="text" [(ngModel)]="sex" (ngModelChange)="changeA($event)">

校验器

pristine   为修改UI中的值,默认为true     干净
dirty       修改过UI的值,默认为false     脏的   
		两个的默认值时相反的
touched     类似触碰,失去焦点,默认是false
untouched  未接触,默认为true
异步验证的时候,表单控件进入 pending状态,默认false,并使用它提供有关正在进行的验证操作的视觉反馈
促发每一个子项是不是纯洁的
.markAsDirty()   // pristine   dirty  一般用这个
促发每一个子项touched是否动过
.markAsTouched/
有效性(就是是否禁用)
    VALID: 该控件通过了所有有效性检查。

    INVALID 该控件至少有一个有效性检查失败了。

    PENDING:该控件正在进行有效性检查,处于中间状态。

    DISABLED:该控件被禁用,豁免了有效性检查。
是否通过校验
.valid
显示报错信息
.errors

一般第二个参数用于校验,给数组整体添加校验

//第一个参数不能与aaa
function simpleValidator(c: AbstractControl): ValidationErrors|null {
  //c.get([0]) 和 c.at(0) 类似
  return c.get([0])!.value === 'aaa' ? null : {'broken': true};
}
//第一个参数必须传
function arrayRequiredValidator(c: AbstractControl): ValidationErrors|null {
  return Validators.required(c.get([0]) as AbstractControl);
}

  this.nameArr.valueChanges.subscribe(res => {
      //是否通过校验
      console.log(this.nameArr.valid);
      // 报错信息
      console.log(this.nameArr.errors);
    })

nameArr: FormArray = new FormArray([
    new FormControl('bb'),
  ],
    [simpleValidator,arrayRequiredValidator]
  )

pending

异步验证的时候,表单控件进入 pending状态,默认false,并使用它提供有关正在进行的验证操作的视觉反馈

function arrayRequiredValidator(c: AbstractControl): ValidationErrors | null {
  return of({name1: true}).pipe(delay(500))
}

 this.profileForm = new FormGroup({
      firstName: new FormControl('xxx', null!, arrayRequiredValidator),
 })
   let aa = this.profileForm.get('firstName') as FormControl;
    console.log(aa.pending);// true
    of(null).pipe(delay(1000)).subscribe(_ => {
      console.log(this.profileForm.get('lastName').pending);// false

    })

markAsPending() 手动设置

    console.log(this.profileForm.get('lastName').pending);//true
    this.profileForm.get('lastName').markAsPending()
    console.log(this.profileForm.get('lastName').pending);// false

	默认直属父级也会被修改为true
		c = new FormControl('value');
		g = new FormGroup({'one': c});
		c.markAsPending();
		g.pending	//true
源码
  markAsPending(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
    (this as {status: string}).status = PENDING;

    if (opts.emitEvent !== false) {
      (this.statusChanges as EventEmitter<any>).emit(this.status);
    }

    if (this._parent && !opts.onlySelf) {
      this._parent.markAsPending(opts);
    }
  }

校验器源码

function isEmptyInputValue(value: any): boolean {
  // 这里我们不检查字符串,所以它也适用于数组
  return value == null || value.length === 0;
}
function hasValidLength(value: any): boolean {
  // 判断有值得
  return value != null && typeof value.length === 'number';
}

疑问为什么有时候可以写单个值,有时候写数组,因为他是第二个参数,多个就写数组,单个就直接写单个值就行了

min
最小值,输入number 比较大小
const control = new FormControl(2, Validators.min(3))
//actual 当前值
console.log(control.errors); // {min: {min: 3, actual: 2}} 

const control = new FormControl(16, Validators.max(15));
console.log(control.errors); // {max: {max: 15, actual: 16}}
可以用来限制min max的number 值

上个源码吧

  static max(max: number): ValidatorFn {
    return (control: AbstractControl): ValidationErrors|null => {
      if (isEmptyInputValue(control.value) || isEmptyInputValue(max)) {
        return null;  // 不要验证空值来允许可选控件
      }
      const value = parseFloat(control.value);
      // 不是NaN然后比较大小
      return !isNaN(value) && value > max ? {'max': {'max': max, 'actual': control.value}} : null;
    };
  }
posted @ 2020-12-30 00:51  猫神甜辣酱  阅读(190)  评论(0编辑  收藏  举报