对于表单页面,首次进入希望不提示错误,只有当用户修改控件内容或焦点离开时再验证,如果不合法显示错误内容。这是正常的做法。但是,如果用户进入界面后什么都不做,直接点击提交按钮,此时需要将所有控件的错误都显示处理。 此文章介绍angualr的实现方式;
首次进入 angular的表单控制基类AbstractControl中提供了丰富的状态字段,我们只需要其中3个状态(其他可以自行查看API文档)
valid:是否合法
dirty:是否是否被修改过
touched:是否获得过焦点 通过这3个状态可以方便实现首次进入不显示错误1 2 3 if (!control.valid && (control.dirty || control.touched) ) { }
或者直接在界面上判断
1 2 3 <div *ngIf ="!control.valid && (control.dirty || control.touched)" > <div *ngIf ="control.hasError('required')" > 代码必填</div > </div >
提交 提交时,需要通过代码修改所有form控制器的状态为dirty(或者touched),这样是为了防止用户没有编辑而直接点击提交也能显示出控件错误。 form控制器基类AbstractControl提供了markAsDirty方法
1 2 3 markAsDirty(opts?: { onlySelf?: boolean ; }): void ;
通过此方法我们可以方便设置控制器的状态
但是markAsDirty方法仅会修改当前控制器和父控制器(递归父控制器,直到parent为空)的状态,并不会修改子控制器的状态,源码如下:
1 2 3 4 5 6 7 markAsDirty(opts: {onlySelf?: boolean } = {}): void { (this as {pristine: boolean }).pristine = false ; if (this ._parent && !opts.onlySelf) { this ._parent.markAsDirty(opts); } }
因此提交时我们需要从Form的根控制器遍历设置子控制器的状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 private submit(): void { if (!this .validateForm.valid) { this .markAsDirtyDeep(this .validateForm); return ; } } public markAsDirtyDeep(control: AbstractControl): void { if (!control) return ; control.markAsDirty(); if (control.hasOwnProperty('controls' )) { let ctrl = <any >control; for (let inner in ctrl.controls) { this .markAsDirtyDeep(ctrl.controls[inner]); } } } }
个人更喜欢下面的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 private submit(): void { if (!this .validateForm.valid) { this .markAsDirtyDeep(this .validateForm); return ; } } public markAsDirtyDeep(control: AbstractControl): void { if (!control) return ; control.markAsDirty(); if (control instanceof FormGroup) { const ctl = <FormGroup>control; for (let inner in ctl.controls) { this .markAsDirtyDeep(ctl.get(inner)); } } else if (control instanceof FormArray) { const ctl = <FormArray>control; for (let inner in ctl.controls) this .markAsDirtyDeep(ctl.get(inner)); } } }
参考: 1、https://github.com/angular/angular/issues/12281 2、https://github.com/angular/angular/issues/11774
v1.5.2