【问题标题】:Angular - Validator on FormGroup breaks single validators on FormControlAngular - FormGroup 上的验证器会破坏 FormControl 上的单个验证器
【发布时间】:2020-07-30 23:08:26
【问题描述】:

我有一个标准的更改密码页面,所以你输入旧密码,然后输入新密码,最后重复新密码。

在“new password”上,我有多个自定义验证器,我还需要一个来检查“new password”是否等于“old password”。

但是我当然不能从FormControl 做到这一点,因为我无法访问“old passwordFormControl,所以我需要在FormGroup 上进行验证。

但是发生的情况是,当它在FormGroup 上验证这部分时,突然“new passwordFormControl 上的所有验证器都被触发!!

有什么原因吗?

 this.myForm = this.formBuilder.group(
      {
        oldPassword: [
          "",
          {
            validators: [Validators.required],
        ],
        newPassword: [
          "",
          Validators.compose([
            Validators.required,
            CustomValidators.patternValidator(/\d/, { hasNumber: true }),
            CustomValidators.patternValidator(/[A-Z]/, {
              hasCapitalCase: true,
            }),
            CustomValidators.patternValidator(/[a-z]/, { hasSmallCase: true }),
            CustomValidators.patternValidator(
              /[ !@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]/,
              { hasSpecialCharacters: true }
            ),
            Validators.minLength(8),
          ]),
        ],
        confirmNewPassword: ["", Validators.compose([Validators.required])],
      },
      { validators: [CustomValidators.passwordMatchValidator] }
    );
  }

我的自定义passwordMatchValidator

static passwordMatchValidator(control: AbstractControl) {
    const password: string = control.get("newPassword").value; 
    const confirmPassword: string = control.get("confirmNewPassword").value; 
    const oldPassword: string = control.get("oldPassword").value;

    if (password !== confirmPassword) {
      control.get("confirmNewPassword").setErrors({ NoPassswordMatch: true });
    }

    if (password === oldPassword) {

   control.get("newPassword").setErrors({ OldPasswordMatch: true });
  }
  }

所以基本上,如果这个 FormGroup 验证器触发了“OldPasswordMatch”错误,那么突然间,newPassword FormControl 上的所有特定验证器都会被触发,这是为什么呢?

我无法将此验证放在FormControlnew password”上,因为它无法访问FormControlold password

【问题讨论】:

  • 不确定您在这里想说什么。除非您设置不同的updateOn 选项,否则表单控件/组上的所有验证器都会一直被评估。无论您在表单组级别做什么。如果表单控件被标记为必需,如果它没有值,它将被标记为无效,并且无论如何都会被标记为具有必需的错误
  • 我要告诉你的是,直到我在 passwordMatchValidator (检查密码 === oldPassword 的那个)上添加第二部分之前,只要添加这两个密码,一切都会正常工作匹配时,不仅会触发验证错误,还会触发上述 FormControl 验证的所有错误,例如 Validators.minLength(8) 将触发,即使匹配的密码只有 2 个字符!为什么会这样?
  • 触发是因为你的密码只有2个字符,最小长度是8??

标签: angular validation


【解决方案1】:

不确定您所说的“所有验证器都在触发”,因为它们一直在验证,但无论如何,您没有正确实施组级验证器。验证器不应该访问控件和设置错误,它们返回 null 或错误对象......因为它是一个组级验证器,它应该更像:

static passwordMatchValidator(control: AbstractControl) {
    const password: string = control.get("newPassword").value; 
    const confirmPassword: string = control.get("confirmNewPassword").value; 
    const oldPassword: string = control.get("oldPassword").value;

    let errors = null;

    if (password !== confirmPassword) {
      errors = { NoPassswordMatch: true };
    }

    if (password === oldPassword) {
      errors = Object.assign(errors || {}, { OldPasswordMatch: true });
    }

    return errors;
}

那么这个错误就会出现在组里。您需要在模板/用户提示中考虑到这一点。

要让您的输入了解角度材料的错误,您必须实现ErrorStateMatcher

import {FormControl, FormGroupDirective, NgForm} from '@angular/forms';
import {ErrorStateMatcher} from '@angular/material/core';

export class GroupErrorStateMatcher implements ErrorStateMatcher {

  constructor(private checkError: string) {}

  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const groupError = form && form.hasError(this.checkError);
    return !!(control && (control.invalid || groupError) && (control.dirty || control.touched));
  }
}

在组件中使用:

oldPasswordMatch =  new GroupErrorStateMatcher('OldPasswordMatch')
noPasswordMatch =  new GroupErrorStateMatcher('NoPassswordMatch')

您将其附加到相应的输入:

<input matInput [errorStateMatcher]="oldPasswordMatch" formControlName="newPassword">

<input matInput [errorStateMatcher]="noPasswordMatch" formControlName="confirmNewPassword">

【讨论】:

  • 对不起,它们不会触发,我说的恰恰相反!您是否看到 FormControl 上的所有验证器都称为“newPassword”,对吗?例如验证器:hasNumber,如果没有号码会触发好吗?现在,一旦我在 passwordMatchValidator 中添加第二个代码块,即以 if (password ===oldPassword) 开头的代码块,现在突然,每当触发此错误时,“新密码”的所有 FormControls 错误将不再触发, 即使例如密码是“test”,oldPassoword 是“test”,也会出现错误,例如 Min length is not 8 and there are no numbers
  • 这更有意义。问题是当你调用 setErrors 时你正在覆盖它们。这就是你不想这样做的部分原因
  • 好的,我明白了,但是我该如何管理呢?遗憾的是,您的解决方案不起作用,我错过了什么吗? myForm 没有收到这些错误(我有一个控制台日志来显示表单的所有错误)
  • 我为你准备了一个 stackblitz stackblitz.com/edit/angular-opqvdi
  • 你可以明白我的意思,首先你应该注释掉自定义验证器组件的第 33 到 35 行,然后你可以看到一切正常,但是如果你取消注释这些行,并尝试把在第一个输入框“string”中,然后在第二个输入框“string”中,您会看到第二个输入的所有验证规则都被丢弃了!
猜你喜欢
  • 2018-07-10
  • 1970-01-01
  • 2017-10-05
  • 1970-01-01
  • 2021-04-19
  • 2019-06-30
  • 2018-06-21
  • 2021-06-24
  • 2020-01-19
相关资源
最近更新 更多