Angular Reactive form:指定 WHEN 验证

Angular Reactive form: specify WHEN to validate

提问人:Wouter Vandenputte 提问时间:10/27/2023 更新时间:10/29/2023 访问量:67

问:

条件验证器可能被问了很多。但是我永远找不到何时调用这个验证器。

假设我有一个只有两个字段的表单

this.form = formBuilder.group({
  emailRequired: [false],
  emailRecipients: ['']
});

我现在希望该字段仅在字段设置为 时才具有必需的验证器。我想出了这个emailRecipientsemailRequiredtrue

const emailRecipientsControl = fb.control('', {
    validators: [
        (x) =>
        {
            // When emailRequired is set to true, the email control is required.
            if (x.parent?.get('emailRequired').value)
            {
                return { required: true }
            };
            return null;
        }
    ]
});
this.form = this.fb.group({
    emailRequired: [false],
    emailRecipients: emailRecipientsControl
});

这实际上在某种程度上是有效的,但问题是我的自定义验证器仅在值已更改时调用,而我需要在两者或已更改时调用它。emailRecipientsemailRecipientsemailRequired

总而言之:如何定义何时调用(自定义)控件验证?

注意:我的真实表单比这个例子大得多,我宁愿不订阅整个表单。

角度 验证 angular-reactive-forms

评论


答:

2赞 MoxxiManagarm 10/27/2023 #1

您需要订阅 valuechanges 并添加/删除验证器。

this.form = formBuilder.group({
  emailRequired: [false],
  emailRecipients: ['']
});

this.form.controls.emailRequired.valueChanges.pipe(
  /*unsubscription*/,
).subscribe(isRequired => {
  if (isRequired) {
    this.form.controls.emailRecipients.addValidators(Validators.required);
  } else {
    this.form.controls.emailRecipients.removeValidators(Validators.required);
  }
  this.form.controls.emailRecipients.updateValueAndValidity();
});

评论

0赞 Eliseo 10/27/2023
请不要删除/添加验证者。有更好的解决方案。在这种情况下,很简单,在复选框的输入中调用“this.form.controls.emailRecipients.updateValueAndValidity()”
0赞 Eliseo 10/29/2023
根据您的建议,我想象了一个“新”解决方案。验证器“checkControl”。我更新我的答案,希望你喜欢:)
0赞 Eliseo 10/27/2023 #2

正如您所说,如果您不使用 setValue 或更改输入,Angular 不会“自动验证”输入。因此,更简单的解决方案是在更改复选框时强制执行此验证

<input type="check" formControlName="emailRequired"
       (input)="form.controls.emailRecipients.updateValueAndValidity()">

更新基于@MoxxiManagarm的推荐。如果我们可以定义我们的 formGroup,并且不需要在需要订阅 valueChanges 或使用(输入)时考虑,那就更好了。

我们可以定义一个“验证器”,如

export function checkControl(controlName:string)
{
  return (x:AbstractControl) =>
  {
    const control=x?.parent?.get(controlName);
    if (control)
      control.updateValueAndValidity()
    return null;
  }
}

这允许我们写

  form = new FormGroup({
    emailRequired: new FormControl(false,checkControl('emailRecipients')),
    emailRecipients: new FormControl('',requireIf('emailRequired'))
  });

然后我们简单

<form [formGroup]="form">
    <input type="checkbox" formControlName="emailRequired">
    <input formControlName="emailRecipients">
    {{form.get('emailRecipients')?.errors|json}}
</form>

注意:验证器“requiredIf”喜欢

export function requireIf(controlName:string)
{
  return (x:AbstractControl) =>
  {
      if (x?.parent?.get(controlName)?.value && !x.value)
      {
          return { required: true }
      };
      return null;
  }
}

看到,当我们更改“复选框”时,formControl 是 updateAndValidity。form.controls.emailRecipiens

好吧,这个“验证器”使典型的重复密码验证器问题更加“健壮”。

export function equalsTo(controlName:string)
{
  return (x:AbstractControl) =>
  {
      const control=x?.parent?.get(controlName);
      if (control && control.value && control.value!=x.value)
      {
          return { notMatch: true }
      };
      return null;
  }
}

表格

  form2=new FormGroup({
    password:new FormControl('',checkControl('repeatPassword')),
    repeatPassword:new FormControl('',equalsTo('password'))

  })

堆栈闪电战

评论

0赞 MoxxiManagarm 10/27/2023
我在这里看到的最大问题来自维护的角度。想象一下,在某个时候,emailRequired 不仅会由用户输入设置,而且还会以编程方式设置。您将始终需要记住,在更改 emailRequired 的每个点上,您还需要更新有效性。这是一个巨大的错误风险。通过列出值本身,您可以一次处理所有这些情况,并且不需要一些自定义验证器。
0赞 Eliseo 10/28/2023
@MoxxiManagarm,但是,为什么在更改时也不只updateValueAndValidity?真的,我不喜欢删除/添加验证器。注意:这只是一个非常非常个人的意见。