Angular2验证器,它依赖于多个表单字段

Sim*_*mon 106 angular

是否可以创建一个可以使用多个值来确定我的字段是否有效的验证器?

例如,如果客户的首选联系方式是通过电子邮件,则应该要求电子邮件字段.

谢谢.


更新了示例代码...


    import {Component, View} from 'angular2/angular2';
    import {FormBuilder, Validators, formDirectives, ControlGroup} from 'angular2/forms';

    @Component({
        selector: 'customer-basic',
        viewInjector: [FormBuilder]
    })
    @View({
        templateUrl: 'app/components/customerBasic/customerBasic.html',
        directives: [formDirectives]
    })
    export class CustomerBasic {
        customerForm: ControlGroup;

        constructor(builder: FormBuilder) {
            this.customerForm = builder.group({
                firstname: [''],
                lastname: [''],
                validateZip: ['yes'],
                zipcode: ['', this.zipCodeValidator] 
                // I only want to validate using the function below if the validateZip control is set to 'yes'
            });
        }

        zipCodeValidator(control) {
            if (!control.value.match(/\d\d\d\d\d(-\d\d\d\d)?/)) {
                return { invalidZipCode: true };
            }
        }

    }
Run Code Online (Sandbox Code Playgroud)

cyb*_*ave 136

为了重申其他方法发布的方法,这就是我创建FormGroup不涉及多个组的验证器的方式.

对于此示例,只需提供passwordconfirmPassword字段的键名称.

// Example use of FormBuilder, FormGroups, and FormControls
this.registrationForm = fb.group({
  dob: ['', Validators.required],
  email: ['', Validators.compose([Validators.required,  emailValidator])],
  password: ['', Validators.required],
  confirmPassword: ['', Validators.required],
  firstName: ['', Validators.required],
  lastName: ['', Validators.required]
}, {validator: matchingPasswords('password', 'confirmPassword')})
Run Code Online (Sandbox Code Playgroud)

为了Validators获取参数,他们需要function使用a FormGroupFormControl参数返回a .在这种情况下,我正在验证一个FormGroup.

function matchingPasswords(passwordKey: string, confirmPasswordKey: string) {
  return (group: FormGroup): {[key: string]: any} => {
    let password = group.controls[passwordKey];
    let confirmPassword = group.controls[confirmPasswordKey];

    if (password.value !== confirmPassword.value) {
      return {
        mismatchedPasswords: true
      };
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

从技术上讲,如果我知道他们的密钥,我可以验证任何两个值,但我更喜欢将其命名Validators为他们将返回的错误.可以修改该函数以获取表示返回的错误的键名的第三个参数.

2016年12月6日更新(v2.2.4)

完整示例:https://embed.plnkr.co/ukwCXm/


Lou*_*ruz 43

戴夫的回答非常非常有帮助.但是,稍作修改可能对某些人有所帮助.

如果您需要向Control字段添加错误,您可以保留表单和验证器的实际构造:

// Example use of FormBuilder, ControlGroups, and Controls
this.registrationForm= fb.group({
  dob: ['', Validators.required],
  email: ['', Validators.compose([Validators.required,  emailValidator])],
  password: ['', Validators.required],
  confirmPassword: ['', Validators.required],
  firstName: ['', Validators.required],
  lastName: ['', Validators.required]
}, {validator: matchingPasswords('password', 'confirmPassword')})
Run Code Online (Sandbox Code Playgroud)

而不是在上面设置错误ControlGroup,在实际字段上执行此操作,如下所示:

function matchingPasswords(passwordKey: string, passwordConfirmationKey: string) {
  return (group: ControlGroup) => {
    let passwordInput = group.controls[passwordKey];
    let passwordConfirmationInput = group.controls[passwordConfirmationKey];
    if (passwordInput.value !== passwordConfirmationInput.value) {
      return passwordConfirmationInput.setErrors({notEquivalent: true})
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 在`else`分支中使用`passwordConfirmationInput.setErrors(passwordConfirmationInput.validator(passwordConfirmationInput))`,当更改为`passwordInput`使数据有效时,使其正确更新. (6认同)
  • 这很有帮助,但我注意到angular文档的返回类型为`{[key:string]:any}`,`setErrors(...)`不返回(不再?).另外`setErrors(...)`会覆盖已经存在的任何错误,所以我附加到当前的错误对象,如:`let errors = formGroup.controls [passwordConfirmationKey] .errors;`和`if(!errors)errors = {};`和`errors ['notEquivalent'] = true;`和`formGroup.controls [dateControlFirst] .setErrors(errors);` (5认同)

Sla*_* II 27

在为多个表单字段实现验证器时,您必须确保在更新每个表单控件时重新评估验证程序.大多数示例都没有为这种情况提供解决方案,但这对于数据一致性和正确行为非常重要.

请参阅我对Angular 2的自定义验证器的实现,它将此考虑在内:https://gist.github.com/slavafomin/17ded0e723a7d3216fb3d8bf845c2f30.

我正在otherControl.valueChanges.subscribe()用来监听其他控件的更改,并thisControl.updateValueAndValidity()在其他控件发生更改时触发另一轮验证.


我正在复制下面的代码以供将来参考:

比赛等,validator.ts

import {FormControl} from '@angular/forms';


export function matchOtherValidator (otherControlName: string) {

  let thisControl: FormControl;
  let otherControl: FormControl;

  return function matchOtherValidate (control: FormControl) {

    if (!control.parent) {
      return null;
    }

    // Initializing the validator.
    if (!thisControl) {
      thisControl = control;
      otherControl = control.parent.get(otherControlName) as FormControl;
      if (!otherControl) {
        throw new Error('matchOtherValidator(): other control is not found in parent group');
      }
      otherControl.valueChanges.subscribe(() => {
        thisControl.updateValueAndValidity();
      });
    }

    if (!otherControl) {
      return null;
    }

    if (otherControl.value !== thisControl.value) {
      return {
        matchOther: true
      };
    }

    return null;

  }

}
Run Code Online (Sandbox Code Playgroud)

用法

以下是如何将其与反应形式一起使用:

private constructForm () {
  this.form = this.formBuilder.group({
    email: ['', [
      Validators.required,
      Validators.email
    ]],
    password: ['', Validators.required],
    repeatPassword: ['', [
      Validators.required,
      matchOtherValidator('password')
    ]]
  });
}
Run Code Online (Sandbox Code Playgroud)

可在此处找到更多最新的验证器:moebius-mlm/ng-validators.


Cha*_*ang 22

我正在使用Angular 2 RC.5但根据Dave的有用答案找不到ControlGroup.我发现FormGroup可以工作.所以我对Dave的代码做了一些小的更新,并且认为我会与其他人分享.

在组件文件中,为FormGroup添加导入:

import {FormGroup} from "@angular/forms";
Run Code Online (Sandbox Code Playgroud)

定义输入以防您需要直接访问表单控件:

oldPassword = new FormControl("", Validators.required);
newPassword = new FormControl("", Validators.required);
newPasswordAgain = new FormControl("", Validators.required);
Run Code Online (Sandbox Code Playgroud)

在构造函数中,实例化您的表单:

this.form = fb.group({
  "oldPassword": this.oldPassword,
  "newPassword": this.newPassword,
  "newPasswordAgain": this.newPasswordAgain
}, {validator: this.matchingPasswords('newPassword', 'newPasswordAgain')});
Run Code Online (Sandbox Code Playgroud)

在您的课程中添加matchingPasswords函数:

matchingPasswords(passwordKey: string, passwordConfirmationKey: string) {
  return (group: FormGroup) => {
    let passwordInput = group.controls[passwordKey];
    let passwordConfirmationInput = group.controls[passwordConfirmationKey];
    if (passwordInput.value !== passwordConfirmationInput.value) {
      return passwordConfirmationInput.setErrors({notEquivalent: true})
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

希望这有助于那些使用RC.5的人.请注意,我还没有在RC.6上测试过.


小智 15

扩展matthewdaniel的答案,因为它不完全正确.这是一些示例代码,显示如何正确地将验证器分配给ControlGroup.

import {Component} from angular2/core
import {FormBuilder, Control, ControlGroup, Validators} from 'angular2/common'

@Component({
  selector: 'my-app',
  template: `
    <form [ngFormModel]="form">
      <label for="name">Name:</label>
      <input id="name" type="text" ngControl="name">
      <br>
      <label for="email">Email:</label>
      <input id="email" type="email" ngControl="email">
      <br>
      <div ngControlGroup="matchingPassword">
        <label for="password">Password:</label>
        <input id="password" type="password" ngControl="password">
        <br>
        <label for="confirmPassword">Confirm Password:</label>
        <input id="confirmPassword" type="password" ngControl="confirmPassword">
      </div>
    </form>
    <p>Valid?: {{form.valid}}</p>
    <pre>{{form.value | json}}</pre>
  `
})
export class App {
  form: ControlGroup
  constructor(fb: FormBuilder) {
    this.form = fb.group({
      name: ['', Validators.required],
      email: ['', Validators.required]
      matchingPassword: fb.group({
        password: ['', Validators.required],
        confirmPassword: ['', Validators.required]
      }, {validator: this.areEqual})
    });
  }

  areEqual(group: ControlGroup) {
    let val;
    let valid = true;

    for (name in group.controls) {
      if (val === undefined) {
        val = group.controls[name].value
      } else {
        if (val !== group.controls[name].value) {
          valid = false;
          break;
        }
      }
    }

    if (valid) {
      return null;
    }

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

这是一个有效的例子:http://plnkr.co/edit/Zcbg2T3tOxYmhxs7vaAm?p=preview

  • 对于任何看这个的人来说,`ControlGroup`被删除,有利于`FormGroup`.[Docs](https://angular.io/docs/ts/latest/api/forms/index/FormGroup-class.html)和[Learn Angular2示例](http://learnangular2.com/forms/#controlgroup) (2认同)

mat*_*iel 14

很多角度源挖掘但我找到了更好的方法.

constructor(...) {
    this.formGroup = builder.group({
        first_name:        ['', Validators.required],
        matching_password: builder.group({
            password: ['', Validators.required],
            confirm:  ['', Validators.required]
        }, this.matchPassword)
    });

    // expose easy access to passworGroup to html
    this.passwordGroup = this.formGroup.controls.matching_password;
}

matchPassword(group): any {
    let password = group.controls.password;
    let confirm = group.controls.confirm;

    // Don't kick in until user touches both fields   
    if (password.pristine || confirm.pristine) {
      return null;
    }

    // Mark group as touched so we can add invalid class easily
    group.markAsTouched();

    if (password.value === confirm.value) {
      return null;
    }

    return {
      isValid: false
    };
}
Run Code Online (Sandbox Code Playgroud)

密码组的HTML部分

<div ng-control-group="matching_password" [class.invalid]="passwordGroup.touched && !passwordGroup.valid">
    <div *ng-if="passwordGroup.touched && !passwordGroup.valid">Passwords must match.</div>
    <div class="form-field">
        <label>Password</label>
        <input type="password" ng-control="password" placeholder="Your password" />
    </div>
    <div class="form-field">
        <label>Password Confirmation</label>
        <input type="password" ng-control="confirm" placeholder="Password Confirmation" />
    </div>
</div>
Run Code Online (Sandbox Code Playgroud)


Bru*_*ilh 0

我认为目前您最好的选择是创建一个表单组来控制您的控件。当您实例化 Control 时,会传入函数来验证它。例子:

    this.password = new Control('', Validators.required);
    let x = this.password;
    this.confirm = new Control('', function(c: Control){
        if(typeof c.value === 'undefined' || c.value == "") return {required: "password required"};
        if(c.value !== x.value)
            return {error: "password mismatch"};
        return null;
    });
Run Code Online (Sandbox Code Playgroud)

我知道这很大程度上取决于您正在运行的 angularjs2 版本。这是针对 2.0.0-alpha.46 进行测试的

如果有人有更好的建议,例如编写自定义验证器(这可能是最好的方法),欢迎。

编辑

您还可以使用 ControlGroup 并完全验证该组。

this.formGroup = new ControlGroup({}, function(c: ControlGroup){
        var pass: Control = <Control>c.controls["password"];
        var conf: Control = <Control>c.controls["confirm"];
        pass.setErrors(null, true);
        if(pass.value != null && pass.value != ""){
            if(conf.value != pass.value){
                pass.setErrors({error: "invalid"}, true);
                return {error: "error"};
            }
        }
        return null;
    });
Run Code Online (Sandbox Code Playgroud)

只需根据您的域编辑消息即可。