两个字段之间的角度条件需要验证器 [英] Angular conditional required validator between two fields

查看:28
本文介绍了两个字段之间的角度条件需要验证器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要对表单进行验证,以便让用户至少填写两个字段之一

I need to have a validation on a form in order to make the user fill at least one of two fields

我尝试过使用这样的自定义验证器:

I've tried with a custom validator like this:

export function conditionalValidator(
  predicate: () => boolean,
  validator: ValidatorFn
): ValidatorFn {
  return formControl => {
    if (!formControl.parent) {
      return null;
    }
    let error = null;
    if (predicate()) {
      error = validator(formControl);
    }        
    return error;
  };
}

然后以我的形式

this.myForm= this.fb.group({
    field1: ['', conditionalValidator(() => !(this.myForm.get('field1').value || this.myForm.get('field2').value), Validators.required)],
    field2: ['', conditionalValidator(() => !(this.myForm.get('field1').value || this.myForm.get('field2').value), Validators.required)],
});

this.myForm.get('field1').valueChanges.subscribe(_ => {
    this.myForm.updateValueAndValidity();
});
this.myForm.get('field2').valueChanges.subscribe(_ => {
    this.myForm.updateValueAndValidity();
});

但我不知道为什么它不起作用

but I don't know why it doesn't work

我还尝试了更手工"的东西方式(此处的stackblitz链接)但也没有运气

I also tried with a more "handcraft" way (stackblitz link here) but with no luck either

推荐答案

正如 mbojko 所说,您可以在整个 formGroup 上创建自定义验证器.这使得验证器在表单中的每次更改时都会执行.如果只有这两个字段就是最优解.

as mbojko say you can makes a custom validator over the whole formGroup. This makes that the validator is executed each change in the form. If only has this two fields is the optima solution.

但是您也可以在一个字段上使用自定义验证器,问题是只有在更改表单控件时才执行验证器,但首先我们要看到验证器

But you can use also a custom validator over one field, the problem is that only execute the validator when change the form control but first we are going to see the validator

export function conditionalValidator(field:string): ValidatorFn {
  return (formControl) => {
    if (!formControl.parent) {
      return null;
    }
    return formControl.value || formControl.parent.get(field).value?
           null: {error:"this field or "+field+" is required"}
  };
}

你使用like

this.myForm = this.fb.group({
  myField: ["",conditionalValidator("otherField")],
  otherField: ["",conditionalValidator("myField")],
});

好吧,正如我所说,当我们将自定义表单控件制作为一个控件中继到另一个控件时的问题是,我们需要检查其他控件何时发生更改.您订阅了控件的 valueChanges.您可以使用 merge rxjs 运算符来获得唯一订阅

Well, As I say, the problem when we makes a custom form control to a control that relay to another is that we need check when the other control has changed. You makes subscribing to valueChanges of the control. You can use merge rxjs operator to have an unique subscribe

merge(this.myForm.get("otherField").valueChanges,
      this.myForm.get("myField").valueChanges)
      .subscribe(_ => {
      this.myForm.get("otherField").updateValueAndValidity({emitEvent:false});
      this.myForm.get("myField").updateValueAndValidity({emitEvent:false})
    });

您的 分叉的stackblitz

Update 好吧,我们知道每次我们的控件发生变化时都会执行验证器,那么为什么不考虑这一点并在此函数中对另一个字段进行 updateValueAndValidity 呢?

Update well, we know that the validator is executed each time ours controls changes, so why don't take account this and makes a updateValueAndValidity of the other field in this function?

好吧,我们只需要在有效且有错误或无效且没有错误时才需要执行,否则我们会得到递归错误

Well, we need executed only if is valid and there're an error or is is invalid and has no error, else we get a recursive error

export function conditionalValidator(field: string): ValidatorFn {
  return formControl => {
    if (!formControl.parent) {
      return null;
    }
    const otherControl = formControl.parent.get(field);
    const error =
      formControl.value || otherControl.value
        ? null
        : { error: "this field or " + field + " is required" };
    if ((error && otherControl.valid) || (!error && otherControl.invalid)) {
      setTimeout(() => {
        otherControl.updateValueAndValidity({ emitEvent: false });
      });
    }
    return error;
  };
}

所以,我们不需要订阅

新的stackblitz

这篇关于两个字段之间的角度条件需要验证器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆