Angular2validation器依赖于多个表单域

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

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

谢谢。


用示例代码更新…


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 }; } } } 

要重申其他已发布的方法,这是我一直在创build不涉及多个组的FormGroupvalidation器的方式。

在这个例子中,只需提供passwordconfirmPassword字段的密钥名称confirmPassword

 // 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')}) 

为了让Validators获取参数,他们需要返回一个FormGroupFormControl作为参数的函数。 在这种情况下,我正在validationFormGroup

 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 }; } } } 

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

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

完整的例子: https : //embed.plnkr.co/ukwCXm/

戴夫的回答非常有帮助。 不过,稍作修改可能会帮助一些人。

如果您需要向“ Control字段添加错误,则可以保留表单和validation程序的实际构造:

 // 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')}) 

而不是在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}) } } } 

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

在您的组件文件中,为FormGroup添加一个导入:

 import {FormGroup} from "@angular/forms"; 

定义您的input,以防需要直接访问表单控件:

 oldPassword = new FormControl("", Validators.required); newPassword = new FormControl("", Validators.required); newPasswordAgain = new FormControl("", Validators.required); 

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

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

在你的类中添加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}) } } } 

希望这有助于那些正在使用RC.5的人。 请注意,我还没有在RC.6上进行testing。

为了扩大matthewdaniel的答案,因为它不完全正确。 下面是一些示例代码,显示了如何正确地将validation器分配给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 }; } } 

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

很多挖angular源,但我find了一个更好的办法。

 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 }; } 

用于密码组的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> 

在为多个表单字段实现validation器时,您必须确保在更新每个表单控件时重新评估validation器。 大多数示例并不提供针对这种情况的解决scheme,但这对于数据一致性和正确的行为非常重要。

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

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


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

比赛等,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; } } 

用法

以下是如何使用反应forms:

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

更新的validation器可以在这里find: moebius-mlm / ng-validators 。

这是另一个我能够想到的方法,它不依赖于整个或子Control而是直接与每个Control绑定。

我遇到的问题是相互依赖的控件没有层次结构,所以我无法创buildControlGroup 。 此外,我的CSS被设置,每个控件将利用现有的angular度类来确定是否显示错误样式,这是更复杂的时候处理组validation,而不是控制特定的validation。 试图确定一个单一的控制是否有效是不可能的,因为validation与控制组相关联,而不是每个单独的控制。

在我的情况下,我想要一个select框的值来确定是否需要另一个字段。

这是使用组件上的Form Builder构build的。 对于select模型,而不是直接将其绑定到请求对象的值,我已经绑定它来获取/设置function,这将允许我处理“更改”事件的控制。 然后,我将能够根据select控件的新值手动设置另一个控件的validation。

这里是相关的视图部分:

 <select [ngFormControl]="form.controls.employee" [(ngModel)]="employeeModel"> <option value="" selected></option> <option value="Yes">Yes</option> <option value="No">No</option> </select> ... <input [ngFormControl]="form.controls.employeeID" type="text" maxlength="255" [(ngModel)]="request.empID" /> 

相关的组成部分:

 export class RequestComponent { form: ControlGroup; request: RequestItem; constructor(private fb: FormBuilder) { this.form = fb.group({ employee: new Control("", Validators.required), empID: new Control("", Validators.compose([Validators.pattern("[0-9]{7}"])) }); get employeeModel() { return this.request.isEmployee; } set employeeModel(value) { this.request.isEmployee = value; if (value === "Yes") { this.form.controls["empID"].validator = Validators.compose([Validators.pattern("[0-9]{7}"), Validators.required]); this.form.controls["empID"].updateValueAndValidity(); } else { this.form.controls["empID"].validator = Validators.compose([Validators.pattern("[0-9]{7}")]); this.form.controls["empID"].updateValueAndValidity(); } } } 

在我的情况下,我总是有一个与控件绑定的模式validation,所以validator总是设置为某些东西,但是我认为如果您没有任何与控件绑定的validator ,则可以将validator设置为null。

更新:还有其他方法捕获模型更改(ngModelChange)=changeFunctionName($event)或通过使用this.form.controls["employee"].valueChanges.subscribe(data => ...))订阅控制值更改this.form.controls["employee"].valueChanges.subscribe(data => ...))

现在我认为你最好的select就是创build一个表单组来保存你的控件。 当你在函数中实例化你的控制过程来validation它。 例:

  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; }); 

我知道这是高度依赖于你正在运行的angularjs2的版本。 这是针对2.0.0-alpha.46进行testing的

如果任何人有更好的消化,如编写自定义validation程序(这可能是最好的方法),这是值得欢迎的。

编辑

您也可以使用ControlGroup并validation整个组。

 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; }); 

只需根据您的域名编辑邮件。

路易斯·克鲁兹的回答对我很有帮助。

要完成刚才添加的setErrors reset:return passwordConfirmationInput.setErrors(null);

而且一切正常!

谢谢,

问候,

TGA

也正在寻找这个,并最终使用了ng2-validation包的equalTo( https://www.npmjs.com/package/ng2-validation

这里是一个例子:Template Driven:

 <input type="password" ngModel name="password" #password="ngModel" required/> <p *ngIf="password.errors?.required">required error</p> <input type="password" ngModel name="certainPassword" #certainPassword="ngModel" [equalTo]="password"/> <p *ngIf="certainPassword.errors?.equalTo">equalTo error</p> 

模型驱动:

 let password = new FormControl('', Validators.required); let certainPassword = new FormControl('', CustomValidators.equalTo(password)); this.form = new FormGroup({ password: password, certainPassword: certainPassword }); 

模板:

 <form [formGroup]="form"> <input type="password" formControlName="password"/> <p *ngIf="form.controls.password.errors?.required">required error</p> <input type="password" formControlName="certainPassword"/> <p *ngIf="form.controls.certainPassword.errors?.equalTo">equalTo error</p> </form> 

这里是我用来确保一个领域的年龄大于或等于另一个领域的年龄的我的版本。 我也使用表单组,所以我使用group.get函数而不是group.get group.controls[]

 import { FormGroup } from '@angular/forms'; export function greaterThanOrEqualTo(sourceKey: string, targetKey: string) { return (group: FormGroup) => { let sourceInput = group.get(sourceKey); let targetInput = group.get(targetKey); console.log(sourceInput); console.log(targetInput); if (targetInput.value < sourceInput.value) { return targetInput.setErrors({ notGreaterThanOrEqualTo: true }) } } } 

而在组件中:

  this.form = this._fb.group({ clientDetails: this._fb.group({ currentAge: ['', [Validators.required, Validators.pattern('^((1[89])|([2-9][0-9])|100)$')]], expectedRetirementAge: ['', [Validators.required]] }), }, { validator: greaterThanOrEqualTo('clientDetails.currentAge', 'clientDetails.expectedRetirementAge') }); 

Angular 4密码匹配validation规则。

如果你需要错误控制领域,那么你可以做到这一点。

 createForm() { this.ngForm = this.fb.group({ 'first_name': ["", Validators.required ], 'last_name' : ["", Validators.compose([Validators.required, Validators.minLength(3)]) ], 'status' : ['active', Validators.compose([Validators.required])], 'phone':[null], 'gender':['male'], 'address':[''], 'email':['', Validators.compose([ Validators.required, Validators.email])], 'password':['', Validators.compose([Validators.required])], 'confirm_password':['', Validators.compose([Validators.required])] }, {validator: this.matchingPassword('password', 'confirm_password')}); } 

那么你需要在constructor方法中声明这个方法就像。

 constructor( private fb: FormBuilder ) { this.createForm(); } 

不要在ControlGroup上设置错误,而是在实际字段上如下所示:

  matchingPassword(passwordKey: string, confirmPasswordKey: string) { return (group: FormGroup): {[key: string]: any} => { let password = group.controls[passwordKey]; let confirm_password = group.controls[confirmPasswordKey]; if (password.value !== confirm_password.value) { return { mismatchedPasswords: true }; } } } 

用于密码组的HTML部分

 <form [formGroup]="ngForm" (ngSubmit)="ngSubmit()"> <div class="form-group"> <label class="control-label" for="inputBasicPassword"> Password <span class="text-danger">*</span></label> <input type="password" class="form-control" formControlName="password" placeholder="Password" name="password" required> <div class="alert text-danger" *ngIf="!ngForm.controls['password'].valid && ngForm.controls['password'].touched">This Field is Required.</div> </div> {{ngForm.value.password | json}} <div class="form-group"> <label class="control-label" for="inputBasicPassword">Confirm Password <span class="text-danger">*</span></label> <input type="password" class="form-control" name="confirm_password" formControlName="confirm_password" placeholder="Confirm Password" match-password="password"> <div class='alert text-danger' *ngIf="ngForm.controls.confirm_password.touched && ngForm.hasError('mismatchedPasswords')"> Passwords doesn't match. </div> </div> <button type="submit" [disabled]="!ngForm.valid" class="btn btn-primary ladda-button" data-plugin="ladda" data-style="expand-left" disabled="disabled"><span class="ladda-label"> <i class="fa fa-save"></i> Create an account <span class="ladda-spinner"></span><div class="ladda-progress" style="width: 0px;"></div> </span><span class="ladda-spinner"></span></button> </form> 

我尝试了大部分的答案,但没有一个为我工作。 我在这里find了一个工作示例https://scotch.io/@ibrahimalsurkhi/match-password-validation-with-angular-2