Angular依赖其他formControl的日期范围验证上下文丢失问题
问题原因
- 初始化时序问题:你在类属性声明阶段直接初始化
dateForm,new FormGroup执行时,两个控件的验证器绑定操作会同步执行,此时整个FormGroup实例还没有完成赋值到this.dateForm的操作,所以this.dateForm自然是undefined,和bind本身无关。 - 代码笔误:验证器内的取值代码
this.dateForm.get('dateForm').value是错误的,你的FormGroup内的控件名是dateFrom,这里写错了控件名,即便时序问题解决也会报错。 - 验证方式不匹配:跨多个关联控件的校验规则,本身就不适合绑定在单个FormControl上,会触发不必要的重复校验,也需要额外处理上下文依赖问题。
推荐解决方案
将日期范围校验作为FormGroup层级的验证器,不需要依赖this上下文,也能直接拿到两个控件的取值,实现起来更简洁可靠:
export class DateRangeSelector { dateForm: FormGroup = new FormGroup({ dateFrom: new FormControl({ year: 2017, month: 10 }), dateTo: new FormControl({ year: 2020, month: 11 }) }, [dateRangeValidator]); // 把验证器绑在FormGroup上 } // 单独抽离验证器,不需要依赖组件实例 function dateRangeValidator(group: FormGroup): { [s: string]: boolean } | null { const valueDateFrom = group.get('dateFrom').value; const valueDateTo = group.get('dateTo').value; if (valueDateFrom && valueDateTo) { const dateFrom = moment(valueDateFrom); const dateTo = moment(valueDateTo); if (dateFrom.isAfter(dateTo)) { return { invalidDate: true }; } } return null; }
校验失败时,错误会挂载在dateForm.errors上,你可以直接通过dateForm.hasError('invalidDate')判断校验结果。
如果你坚持要绑定到单个控件的解决方法
如果你确实需要将错误挂载在单个控件上,可以将验证器的绑定操作放到ngOnInit生命周期中执行,此时dateForm已经完成初始化:
export class DateRangeSelector implements OnInit { dateForm: FormGroup = new FormGroup({ dateFrom: new FormControl({ year: 2017, month: 10 }), dateTo: new FormControl({ year: 2020, month: 11 }) }); ngOnInit() { // 等dateForm初始化完成后再添加验证器,此时this.dateForm已存在 this.dateForm.get('dateFrom').addValidators([this.dateValidator.bind(this)]); this.dateForm.get('dateTo').addValidators([this.dateValidator.bind(this)]); // 手动触发一次校验更新状态 this.dateForm.get('dateFrom').updateValueAndValidity(); this.dateForm.get('dateTo').updateValueAndValidity(); } dateValidator(control: FormControl): { [s: string]: boolean } | null { // 修正这里的控件名笔误,原来是dateForm,要改成dateFrom const valueDateFrom = this.dateForm.get('dateFrom').value; const valueDateTo = this.dateForm.get('dateTo').value; if (valueDateFrom && valueDateTo) { const dateFrom = moment(valueDateFrom); const dateTo = moment(valueDateTo); if (dateFrom.isAfter(dateTo)) { return { invalidDate: true }; } } return null; } }
内容的提问来源于stack exchange,提问作者César Castro Aroche
相关产品推荐
相关产品推荐

