【问题标题】:Performing cross-field validation on Angular 2 Reactive Forms在 Angular 2 Reactive Forms 上执行跨字段验证
【发布时间】:2017-03-10 04:45:57
【问题描述】:

我正在尝试使用 Reactive Forms 模块在 Angular 2 中构建一个注册表单。因此,我为表单定义了一个 FormGroup,然后我可以为其中的每个 FormControl 列出验证器。

考虑这个部分类:

export class TestFormComponent implements OnInit {
  form: FormGroup;
  password = new FormControl("", [Validators.required]);
  passwordConfirm = new FormControl("", [Validators.required, this.validatePasswordConfirmation]);

  constructor(private fb: FormBuilder) {
  }

  ngOnInit() {
    this.form = this.fb.group({
      "password": this.password,
      "passwordConfirm": this.passwordConfirm
    });
  }

  validatePasswordConfirmation(fc: FormControl) {
    var pw2 = fc.value;
    var pw = // how do I get this value properly????

    if (pw === '') {
      return {err:"Password is blank"};
    }

    if (pw2 === '') {
      return {err:"Confirmation password is blank"};
    }

    if (pw !== pw2) {
      return {err:"Passwords do not match"}
    }

    return null;
  }
}

您可以看到我为passwordConfirm 字段创建了一个验证器,但我不知道如何获取主password 字段的值(用作验证器中的pw)来执行比较。

我不能只引用this.form.value.password,因为验证器中的this 不引用包含表单的主类。

有什么想法吗?

【问题讨论】:

标签: angular typescript angular2-forms


【解决方案1】:

所以答案是在整个表单上放置一个新的验证器,然后使用传递给验证器的 FormGroup 对象作为比较字段值的一种方式。这就是我所怀疑的。但是,我缺少的是如何在单个 passwordConfirm 字段上正确设置错误状态。这段代码展示了如何做到这一点:

export class TestFormComponent implements OnInit {
  form: FormGroup;
  password = new FormControl("", [Validators.required]);
  passwordConfirm = new FormControl("", [Validators.required, this.validatePasswordConfirmation]);

  constructor(private fb: FormBuilder) {
  }

  ngOnInit() {
    this.form = this.fb.group({
      "password": this.password,
      "passwordConfirm": this.passwordConfirm
    },
    {
      validator: this.validatePasswordConfirmation
    });
  }

  validatePasswordConfirmation(group: FormGroup) {
    var pw = group.controls['password'];
    var pw2 = group.controls['passwordConfirm'];

    if (pw.value !== pw2.value) { // this is the trick
      pw2.setErrors({validatePasswordConfirmation: true});
    }

    // even though there was an error, we still return null
    // since the new error state was set on the individual field
    return null; 
  }
}

如上面代码中的注释所述,诀窍是您可以使用setErrors() 方法在各个FormControl 字段上设置错误状态。所以现在,有了这段代码,确认字段会根据它拥有的常规验证器(如Validators.required)以及我们添加的基于自定义表单的验证器获取正确的有效/无效状态集。

使用此方法,您可以创建复杂的基于表单的验证器,这些验证器可以检查许多不同表单字段的状态,并根据您可以提出的任何业务逻辑分别设置每个字段的验证状态。这使得使用 Angular 2 Reactive 表单的跨字段验证变得非常简单。

【讨论】:

  • 另一种选择是有一个自定义验证器,它将接受一个 FormControlNames 数组,并从那里相应地验证它们。见Question: angular2-forms-validator-with-interrelated-fields
  • 我对此做了一个调整:在设置它之前重置 pw2 错误,因此当更新 pw1 以匹配 pw2(而不是更新 pw2 以匹配 pw1)时,它会按预期工作。在if (pw.value... 的正上方,我包括了if (pw2.errors) { pw2.errors['validatePasswordConfirmation'] = null }。感谢贡献前 99%!
  • 我有一个类似的用例,但有条件可见的输入。您的方法中唯一缺少的是将错误重置为空:pw2.setErrors(pw.value !== pw2.value ? {validatePasswordConfirmation: true} : null);
【解决方案2】:

如果 pw2 字段本身有验证器,pw2.setErrors(null); 会导致问题,例如minLength

  ngOnInit() {
    this.form = this.fb.group({
      "password": [this.password, Validators.minLength(6)],
      "passwordConfirm": [this.passwordConfirm, Validators.minLength(6)]
    },
    {
      validator: this.validatePasswordConfirmation
    });
  }

setErrors(null) 将破坏 minLength 警告。

最好是跨字段验证器 validatePasswordConfirmation() 返回错误,因为 where 错误出现在 HTML 中 -- 单个字段旁边,或整个表单的上方/下方——无论如何,这完全在我们的控制之下。

<div *ngIf="myNgForm.submitted" class="text-error">
    <span *ngIf="form.errors?.validatePasswordConfirmation">This field must match the first field</span>
    <span *ngIf="form.controls.passwordConfirm.errors?.minlength">must be at least 6 chars</span>
</div>

【讨论】:

    【解决方案3】:

    Michael Oryl 的回答在我的情况下有两个错误,也许我使用不同的版本(Angular 2.3.0):

    1。 passwordConfirm = new FormControl("", [Validators.required, this.validatePasswordConfirmation]);

    应该是:

    passwordConfirm = new FormControl("", [Validators.required]);
    

    因为:

    validatePasswordConfirmation(group: FormGroup)
    

    与 FormGroup 的子元素一起触发。我不知道为什么,但它发生了。所以整个组的第二个验证器就足够了,因为它会与整个 FormGroup 一起触发。

    1. 在重复字段之后编辑原始字段并且两个字段相等时,Michaels 代码保持错误状态。 在这种情况下,这段代码在更复杂的验证中完成了工作,您需要更复杂的东西:

      if (pw.value != pw2.value) {
        pw2.setErrors({validatePasswordConfirmation: true});
      }
      else{
        pw2.setErrors(null);
      }
      

    完整代码:

    export class TestFormComponent implements OnInit {
      form: FormGroup;
      password = new FormControl("", [Validators.required]);
      passwordConfirm = new FormControl("", [Validators.required]);
    
      constructor(private fb: FormBuilder) {
      }
    
      ngOnInit() {
        this.form = this.fb.group({
          "password": this.password,
          "passwordConfirm": this.passwordConfirm
        },
        {
          validator: this.validatePasswordConfirmation
        });
      }
    
      validatePasswordConfirmation(group: FormGroup) {
        var pw = group.controls['password'];
        var pw2 = group.controls['passwordConfirm'];
    
        if (pw.value !== pw2.value) { // this is the trick
          pw2.setErrors({validatePasswordConfirmation: true});
        }else{
          pw2.setErrors(null);
        }
    
        return null; 
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      • 1970-01-01
      • 2023-03-04
      • 2021-08-30
      • 2018-08-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多