Angular2中的交叉字段验证

Coa*_*den 19 javascript validation angular

我正在构建一个Angular2客户端应用程序.我目前正在研究成员资格组件,并将客户端组件与MVC6 vNext Identity v3集成.我编写了自定义Angular2密码验证器,如下所示:

needsCapitalLetter(ctrl: Control): {[s: string]: boolean} {
    if(!ctrl.value.match(/[A-Z]/))
        return {'needsCapitalLetter': true}

    return null;
}

needsLowerLetter(ctrl: Control): {[s: string]: boolean} {
    if(!ctrl.value.match(/[a-z]/))
        return {'needsLowerLetter': true}

    return null;            
}

needsNumber(ctrl: Control): {[s: string]: boolean} {
    if(!ctrl.value.match(/\d/))
        return {'needsNumber': true}

    return null;            
}

needsSpecialCharacter(ctrl: Control): {[s: string]: boolean} {
    if(!ctrl.value.match(/[^a-zA-Z\d]/))
        return {'needsSpecialCharacter': true}

    return null;            
}
Run Code Online (Sandbox Code Playgroud)

这项工作很棒,而且我很喜欢Angular2,但现在我正在尝试编写一个验证器来验证"确认密码"是否等于"密码".为了做到这一点,我需要能够相对于另一个验证一个字段.我可以在组件级别轻松完成此操作,只需检查模糊,提交或其他任何方式,但这会绕过Angular2 ngForm验证系统.我非常想弄清楚如何为一个可以检查另一个字段的值的字段编写一个Angular2 Validator,方法是传入另一个字段的名称或者接近它的东西.看起来这应该是一种能力,因为这在几乎任何复杂的业务应用程序UI中都是必需的.

Thi*_*ier 28

您需要将自定义验证程序分配给完整的表单组以实现此目的.像这样的东西:

this.form = this.fb.group({
  name:  ['', Validators.required],
  email: ['', Validators.required]
  matchingPasswords: this.fb.group({
    password:        ['', Validators.required],
    confirmPassword: ['', Validators.required]
  }, {validator: this.matchValidator})  <--------
});
Run Code Online (Sandbox Code Playgroud)

这样您就可以访问该组的所有控件,而不仅仅是一个...这可以使用controlsFormGroup 的属性进行访问.触发验证时提供FormGroup.例如:

matchValidator(group: FormGroup) {
  var valid = false;

  for (name in group.controls) {
    var val = group.controls[name].value
    (...)
  }

  if (valid) {
    return null;
  }

  return {
    mismatch: true
  };
}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅此问题:

  • 这里很少更新.在最新的Angular 2中,`ControlGroup`被重命名为`FormGroup` (4认同)

Die*_*nue 13

您还可以使用自定义指令验证程序来比较字段.

在你的HTML中:

<div>
    <label>Password</label>
    <input type="password" name="password" [ngModel]="user.password" 
        required #password="ngModel">
    <small [hidden]="password.valid || (password.pristine && !f.submitted)">
        Password is required
    </small>
</div>
<div>
    <label>Retype password</label>
    <input type="password" name="confirmPassword" [ngModel]="user.confirmPassword" 
        required validateEqual="password" #confirmPassword="ngModel">
    <small [hidden]="confirmPassword.valid ||  (confirmPassword.pristine && !f.submitted)">
        Password mismatch
    </small>
</div>
Run Code Online (Sandbox Code Playgroud)

而你的指令:

import { Directive, forwardRef, Attribute } from '@angular/core';
import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms';
@Directive({
    selector: '[validateEqual][formControlName],[validateEqual][formControl],[validateEqual][ngModel]',
    providers: [
        { provide: NG_VALIDATORS, useExisting: forwardRef(() => EqualValidator), multi: true }
    ]
})
export class EqualValidator implements Validator {
    constructor( @Attribute('validateEqual') public validateEqual: string) {}

    validate(c: AbstractControl): { [key: string]: any } {
        // self value (e.g. retype password)
        let v = c.value;

        // control value (e.g. password)
        let e = c.root.get(this.validateEqual);

        // value not equal
        if (e && v !== e.value) return {
            validateEqual: false
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是plunkr的完整解决方案:

https://plnkr.co/edit/KgjSTj7VqbWMnRdYZdxM?p=preview