Angular 2表单validation重复密码

请参考这个关于validation器中比较字段与angular2的问题 。 不幸的是,Angular 2改变了一点,所以解决scheme似乎不再工作。 这是我的代码:

import {IonicApp,Page,NavController,NavParams} from 'ionic/ionic' import {Component} from 'angular2/core' import {FORM_PROVIDERS, FormBuilder, Validators} from 'angular2/common' import {ControlMessages} from '../../components/control-messages' import {ValidationService} from '../../services/validation-service' @Page({ templateUrl: 'build/pages/account/register.html', directives: [ControlMessages] }) export class RegisterPage { constructor(nav:NavController,private builder: FormBuilder) { this.nav = nav this.registerForm = this.builder.group({ 'name' : ['', Validators.required], 'email' : ['',Validators.compose([Validators.required, ValidationService.emailValidator])], 'password' : ['',Validators.required], 'repeat' : ['',this.customValidator] } ) } register() { alert(this.registerForm.value.password) } private customValidator(control) { //console.log(this.registerForm.value.password) //return {isEqual: control.value === this.registerForm.value.password} return true } } 

我的html:

 <ion-content class="account"> <ion-list padding> <form [ngFormModel]='registerForm' (submit)='register()'> <div class="centered"> <img class="logo" src="img/logo.png" alt=""> </div> <div class="spacer" style="height: 20px;"></div> <ion-input> <ion-label floating>Name</ion-label> <input type="text" ngControl='name' id='name'> <control-messages control="name"></control-messages> </ion-input> <ion-input> <ion-label floating>Email</ion-label> <input type="email" ngControl='email' id='email'> <control-messages control="email"></control-messages> </ion-input> <ion-input> <ion-label floating>Password</ion-label> <input type="password" ngControl='password' id='password' value=""> <control-messages control="password"></control-messages> </ion-input> <ion-input> <ion-label floating>Confirm Password</ion-label> <input type="password" ngControl='repeat' id='repeat'> <control-messages control="repeat"></control-messages> </ion-input> <button class="calm" full type='submit' [disabled]='!registerForm.valid'>Register</button> <ion-item style="background-color:transparent;border:none;"> <button class="text-button" clear item-right (click)="gotoLogin()">Have an account already, Login</button> </ion-item> </form> </ion-list> </ion-content> 

但不幸的是,我无法访问我的validationfunction中的“密码”值。 如果我取消注释console.log(this.registerForm.value.password) ,然后我得到以下错误信息:

例外:TypeError:无法读取未定义的属性“值”

任何想法? 谢谢。

我在代码中看到了几个问题。 您尝试在validation程序function中使用this关键字,这不对应于组件的实例。 这是因为您将它设置为validation器函数时引用该函数。

而且,与控件相关的值可以在value属性中达到。

也就是说,我认为一起validation两个字段的正确方法是创build一个组,并将validation器关联在一起:

 this.registerForm = this.builder.group({ 'name' : ['', Validators.required], 'email' : ['',Validators.compose([Validators.required, ValidationService.emailValidator])], 'passwords': fb.group({ password: ['', Validators.required], repeat: ['', Validators.required] }, {validator: this.areEqual}) }); 

这样你就可以访问组的所有控件,而不仅仅是一个,不需要再使用this关键字…这可以通过组控件的controls属性来访问。 后者(不是一个)在validation触发时直接提供。 例如:

 areEqual(group: ControlGroup) { var valid = false; for (name in group.controls) { var val = group.controls[name].value (...) } if (valid) { return null; } return { areEqual: true }; } 

更多详细信息,请参阅以下内容:

  • 在Angular2中进行交叉字段validation

编辑

要显示错误,您可以简单地使用以下内容:

 <span *ngIf="!registerForm.passwords.valid" class="help-block text-danger"> <div *ngIf="registerForm.passwords?.errors?.areEqual"> The two passwords aren't the same </div> </span> 

我已经为Angular 4实现了一个自定义密码匹配validation器。

除了检查两个值是否匹配之外,还会订阅其他控件的更改,并在两个控件中的任何一个更新时重新validation。 随意使用它作为你自己的实现的参考或直接复制它。

以下是解决scheme的链接: https //gist.github.com/slavafomin/17ded0e723a7d3216fb3d8bf845c2f30 。


在这里,我提供了一个代码的副本:

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

发现更简单的解决scheme。 不知道这是否正确的做法,但它对我有用

 <!-- PASSWORD --> <ion-item [ngClass]="{'has-error': !signupForm.controls.password.valid && signupForm.controls.password.dirty}"> <ion-input formControlName="password" type="password" placeholder="{{ 'SIGNUP.PASSWORD' | translate }}" [(ngModel)]="registerCredentials.password"></ion-input> </ion-item> <!-- VERIFY PASSWORD --> <ion-item [ngClass]="{'has-error': !signupForm.controls.verify.valid && signupForm.controls.verify.dirty}"> <ion-input formControlName="verify" [(ngModel)]="registerCredentials.verify" type="password" pattern="{{registerCredentials.password}}" placeholder="{{ 'SIGNUP.VERIFY' | translate }}"> </ion-input> </ion-item> 

看到

 pattern="{{registerCredentials.password}}" 

如果您使用RC.5并且找不到ControlGroup,则可以尝试使用FormGroup。 您可以从我的回答中find更多信息:

Angular 2 RC.5表单validation密码重复

Angular 4.3.3解决scheme!

你可以这样做: [formGroup]formGroupNameformControlName在HTML和new FormGroupnew FormControl和自定义的areEqual方法在TS

reg.component.html

 <div [formGroup]="userFormPassword"> <div> <input formControlName="current_password" type="password" placeholder="Current Password"> </div> <div formGroupName="passwords"> <input formControlName="new_password" type="password" placeholder="New Password"> </div> <div formGroupName="passwords"> <input formControlName="repeat_new_password" type="password" class="form-control" placeholder="Repeat New Password"> <div class="input-error" *ngIf=" userFormPassword.controls['passwords'].errors && userFormPassword.controls['passwords'].errors.areEqual && userFormPassword.controls['passwords'].controls.repeat_new_password.touched && userFormPassword.controls['passwords'].controls.new_password.touched ">PASSWORDS do not match </div> </div> </div> 

reg.component.ts

 export class HomeHeaderSettingsModalComponent implements OnInit { userFormPassword: FormGroup; // ... static areEqual(c: AbstractControl): ValidationErrors | null { const keys: string[] = Object.keys(c.value); for (const i in keys) { if (i !== '0' && c.value[ keys[ +i - 1 ] ] !== c.value[ keys[ i ] ]) { return { areEqual: true }; } } } ngOnInit() { this.userFormPassword = new FormGroup({ 'current_password': new FormControl(this.user.current_password, [ Validators.required, ]), 'passwords': new FormGroup({ 'new_password': new FormControl(this.user.new_password, [ Validators.required ]), 'repeat_new_password': new FormControl(this.user.repeat_new_password, [ Validators.required ]) }, HomeHeaderSettingsModalComponent.areEqual) }); } } 

结果: 结果

通过使用这个库ng2-validation-manager你可以很容易地做到这一点:

 this.form = new ValidationManager({ 'password' : 'required|rangeLength:8,50', 'repassword' : 'required|equalTo:password' }); 

而且,对于forms为0.2.0的angular度2 rc4,需要标记和属性来调用用于包含分组input的组名,以防止错误

 <div formGroupName="passwords">group input fields here... </div> 

那么,我在这个话题上寻找答案,所有的都太大了,我的懒惰,所以我这样做。 我觉得这个工作做得很好。

我用ngModel来绑定密码和repeatPasswordinput,然后我用angular度2中的[hidden]属性显示或隐藏了密码比较消息的div。

  <label for="usr">Password</label> <input placeholder="12345" id="password" type="text" class="form-control" [(ngModel)]="password"> <label for="usr">Repeat pasword</label> <input placeholder="12345" type="text" class="form-control" [(ngModel)]="repeatPassword"> <div [hidden]="password == repeatPassword">Passwords do not match!</div> 

将密码保存到实例variables中。

  password = new FormControl('', [Validators.required]); 

然后在你的表单组中使用它。

  this.registrationForm = this.fb.group({ 'email': ['', [ Validators.required, NGValidators.isEmail, ] ], 'password': this.password, 'password2': ['', [Validators.required, this.passwordMatch]] }); 

所以这个函数看起来像这样。

  private passwordMatch() { let that = this; return (c: FormControl) => { return (c.value == that.password.value) ? null : {'passwordMatch': {valid: false}}; } } 

我知道这不是最好的解决scheme,但它的工作!

这是我使用Angular Validators的方式

零件:

 import { UserModel } from '../../settings/users/user.model'; import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FormRequestModel } from '../Shared/form.model'; import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-add-user', templateUrl: './add-user.component.html', styleUrls: ['./add-user.component.scss'] }) export class AddUserComponent implements OnInit { passwordsForm: FormGroup; user: UserModel; constructor(private fb: FormBuilder) { } ngOnInit() { this.passwordsForm = this.fb.group({ inputPassword: ['', Validators.compose([Validators.required, Validators.minLength(6), Validators.maxLength(50)])], inputPasswordAgain: [''] }); } } 

HTML:

  <form class="form-horizontal" [formGroup]="passwordsForm" novalidate> <div class="form-group"> <br/> <label for="inputPassword" class="col-sm-2 control-label">Password</label> <div class="col-sm-10"> <input type="password" formControlName="inputPassword" class="form-control" id="inputPassword" placeholder="Password"> </div> </div> <div class="alert alert-danger" *ngIf="!passwordsForm.controls['inputPassword'].valid && passwordsForm.controls['inputPassword'].touched">Password must contain at least 6 characters!!</div> <div class="form-group"> <br/> <label for="inputPasswordAgain" class="col-sm-2 control-label">Password again</label> <div class="col-sm-10"> <input type="password" formControlName="inputPasswordAgain" class="form-control" id="inputPasswordAgain" placeholder="Password again"> </div> </div> <!-- Show div warning element if both inputs does not match the validation rules below --> <div class="alert alert-danger" *ngIf="passwordsForm.controls['inputPasswordAgain'].touched && passwordsForm.controls['inputPasswordAgain'].value !== passwordsForm.controls['inputPassword'].value"> Both passwords must be equal!</div> 

我发现了一个解决scheme,让我更快乐的代码一致性error handling:

第一:用一个静态方法创build一个自定义的validation类,进行validation

这个方法应该有一个angular度注入的AbstractControl参数

请注意,您将在ConfirmPassword控件中传递此消息,因此您需要调用父进程到FormGroup。 从那里你可以调用formGroup.get('myControl')并获得密码的控件,并在创build表单组时按照你的名字进行确认。

 import {AbstractControl} from '@angular/forms'; export class PasswordValidation { static MatchPassword(AC: AbstractControl) { const formGroup = AC.parent; if (formGroup) { const passwordControl = formGroup.get('Password'); // to get value in input tag const confirmPasswordControl = formGroup.get('Confirm'); // to get value in input tag if (passwordControl && confirmPasswordControl) { const password = passwordControl.value; const confirmPassword = confirmPasswordControl.value; if (password !== confirmPassword) { return { matchPassword: true }; } else { return null; } } } return null; } } 

第二:使用你的客户validation器就像你使用angulars

 this.registerForm = this.fb.group({ // <-- the parent FormGroup Email: ['', Validators.required ], Username: ['', Validators.required ], FirstName: ['', Validators.required ], Password: ['', [ Validators.required, Validators.minLength(6) ] ], Confirm: ['', [ Validators.required, PasswordValidation.MatchPassword ] ] }); 

然后,Angular将添加'matchPassword':true确认您的Confirm控件错误,因为它会在缺less值时添加'required'true

我的解决scheme为Angular 4.3.4,它不需要额外的FormGroup

  • 如果密码相同,则注册用于repeatedPassword密码检查的自定义validation器
  • 在创build表单时在password.valueChanges上订阅处理程序,并在repeatedPassword password.valueChanges调用.updateValueAndValidity() method

这里是一些代码:

 form: FormGroup passwordFieldName = 'password' repeatedPasswordFieldName = 'repeatedPassword' createForm() { this.form = this.formBuilder.group({ login: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(255), Validators.email]], [passwordFieldName]: ['', [Validators.required, Validators.minLength(6), Validators.maxLength(255)]], [repeatedPasswordFieldName]: ['', [Validators.required, this.samePassword]] }); this.form .get(passwordFieldName) .valueChanges.subscribe(() => { this.form .get(repeatedPasswordFieldName).updateValueAndValidity(); }) } samePassword(control: FormControl) { if (!control || !control.parent) { return null; } if (control.value !== control.parent.get(passwordFieldName).value) { return {'passwordMismatch': true} } return null; } 

我只想发布我的解决scheme:

 this.authorizationSettings = formBuilder.group({ currentPassword: [null, Validators.compose([Validators.required, Validators.minLength(8)])], newPassword: [null, Validators.compose([Validators.required, Validators.minLength(8)])], repeatNewPassword: [null] }); this.authorizationSettings.controls.newPassword.valueChanges.subscribe(data => { if (data) { data = data.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'); } this.authorizationSettings.controls.repeatNewPassword .clearValidators(); this.authorizationSettings.controls.repeatNewPassword .setValidators(Validators.compose([Validators.required, Validators.pattern(data)])); }); 

我们需要先创build表单组,然后订阅第一个新的密码字段,然后添加validation重复字段。

刚从Angular开始,我发现这个解决scheme,不知道是否是好的做法,你:

  // Custom password confirmation validation static matchFieldValidator(fieldToMatch:string) : ValidatorFn { return (control : AbstractControl) : { [key: string]: any;} => { let confirmField = control.root.get(fieldToMatch); return (confirmField && control.value !== confirmField.value) ? {match:false} : null; } } 

这样,您可以在设置validation规则时做这样的事情

  this.registrationForm = fb.group({ ... password1 : ['', [Validators.minLength(3)]], // remember to replace RegisterComponent with YOUR class name password2 : ['', [RegisterComponent.matchFieldValidator('password1')]], }); 

概要

  • 每当其他控件的值发生变化时触发validation。
  • 取消订阅以避免内存泄漏
  • 返回{match: true}将允许我们检查一个给定的控件是否有使用myControl.hasError('match')的错误

履行

 import { AbstractControl, ValidatorFn } from '@angular/forms'; import { Subscription } from 'rxjs/Subscription'; export function matchOtherValidator(otherControlName: string): ValidatorFn { return (control: AbstractControl): { [key: string]: any } => { const otherControl: AbstractControl = control.root.get(otherControlName); if (otherControl) { const subscription: Subscription = otherControl .valueChanges .subscribe(() => { control.updateValueAndValidity(); subscription.unsubscribe(); }); } return (otherControl && control.value !== otherControl.value) ? {match: true} : null; }; } 

 this.registerForm = formBuilder.group({ email: ['', [ Validators.required, Validators.email ]], password: ['', [ Validators.required, Validators.minLength(8) ]], confirmPassword: ['', [ Validators.required, matchOtherValidator('password') ]] });