0%

angular响应式表单交叉验证

自从用了angular响应式表单,面对各种验证方便的不要不要的。但是发现了一个问题,那就是表单的交叉验证。我们在添加响应式表单的时候,在ts文件中都是对单个字段添加验证,那我们交叉验证怎么办?

多个字段的交叉验证?

具体表现为:假设有两个字段,任何一个字段和初始字段不一样的时候,button就可点击,否则就禁用button。

那我们可以立马想到,给需要监控的字段添加监控函数,字段变更后去处理button。这很easy啊,但是我们使用了响应式表单了,能用验证器就用验证器,不要单独加验证函数。

那是不是有跨字段交叉验证的方法呢?看看文档,还真有:

1
2
3
4
5
const heroForm = new FormGroup({
'name': new FormControl(),
'alterEgo': new FormControl(),
'power': new FormControl()
}, { validators: identityRevealedValidator });

如上所示,想要在单个的自定义验证器中计算两个字段控件,就需要在它们的共同的FormGrop中进行验证。这样,我们就可以在一个验证器中同时校验两个控件的值。

看看自定义验证器的代码:

1
2
3
4
5
export const identityRevealedValidator: ValidatorFn = (control: FormGroup): ValidationErrors | null => {
const name = control.get('name');
const alterEgo = control.get('alterEgo');
return name && alterEgo && name.value === alterEgo.value ? { 'identityRevealed': true } : null;
};

这个验证器实现了ValidatorFn接口,接收一个angular表单控件对象为参数,当表单有效时,返回一个null,否则返回ValidationErrors对象。

来看看我的业务代码:

1
2
3
4
5
6
7
8
9
10
constructor(
private fb: FormBuilder,
) {}
this.validateForm = this.fb.group({
userName: [this.data.userName, [Validators.required]],
currencies: [this.data.currencies, [Validators.required]],
googleAuth: [null, [Validators.required]],
}, {
validators: this.testValidator,
});

蛋疼的是,我按照文档里面加上去后,都不起作用,验证器里输出也没有任何东西,那说明验证器没有正确设置啊,我想应该是我用了FormBuilder.group的缘故,可能和直接new FormGroup的方式不一样,查看下FormBuilder.group的参数看看发现有一行注释:

validator: A synchronous validator function, or an array of validator functions

好吧,原来是有出入,后面的验证器的key应当为validator。来正确的设置:

1
2
3
4
5
6
7
this.validateForm = this.fb.group({
userName: [this.data.userName, [Validators.required]],
currencies: [this.data.currencies, [Validators.required]],
googleAuth: [null, [Validators.required]],
}, {
validator: this.testValidator,
});

对的,你没看错,如果是表单级的验证器的话,key应当为validator而不是validators

再看看我们的业务:

1
2
3
4
5
6
7
8
9
10
11
testValidator:ValidatorFn = (control: FormGroup): ValidationErrors | null => {
const name = control.get('userName');
const currencies = control.get('currencies');
if (name.value !== this.data.userName || String(currencies.value) !== this.data.currencies) {
console.log('ok')
this.modal['nzFooter'][1].disabled = false;
} else {
this.modal['nzFooter'][1].disabled = true;
}
return null;
};

我这里只需要来验证字段判断button,和表单没啥关系,所以默认返回null,其他的都是业务相关的逻辑。

PS:这里用了ant.design的模态框,注入NzModalRef即可动态改变模态框的设置内容。

码字辛苦,打赏个咖啡☕️可好?💘