Javascript 用于密码的反应形式的自定义验证器并确认密码匹配将未定义的参数导入 Angular 4
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44449673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Custom Validator on reactive form for password and confirm password matching getting undefined parameters into Angular 4
提问by Juan
I'm trying to implement a custom validator to check if the password and password confirm are equal. The problem is that the validator is getting undefined password and confirmedPassword parameters. How do I make this work. The function works cause if I change the condition to === instead of !== it throws the error correctly when the fields are the same. Does anyone know which is the error here?
我正在尝试实现一个自定义验证器来检查密码和密码确认是否相等。问题是验证器正在获取未定义的密码和confirmedPassword 参数。我如何使这项工作。如果我将条件更改为 === 而不是 !== 它会在字段相同时正确抛出错误,因此该函数会起作用。有谁知道这里的错误是什么?
signup.component.html
注册.component.html
<div class="col-md-7 col-md-offset-1 col-sm-7">
<div class="block">
<div class="well">
<form (onSubmit)="onSubmit()" [formGroup]="signUpForm">
<div class="form-group">
<label for="username" class="control-label">Nombre de usuario:</label>
<input type="text" class="form-control" formControlName="username" title="Please enter your username" placeholder="username">
<p class="help-block" *ngIf="signUpForm.get('username').hasError('required') && signUpForm.get('username').touched">El nombre de usuario es obligatorio</p>
<p class="help-block" *ngIf="signUpForm.get('username').hasError('minlength') && signUpForm.get('username').touched">El nombre de usuario debe tener al menos 6 caracteres</p>
<p class="help-block" *ngIf="signUpForm.get('username').hasError('maxlength') && signUpForm.get('username').touched">El nombre de usuario debe tener menos de 15 caracteres</p>
</div>
<div class="form-group">
<label for="email" class="control-label">E-mail:</label>
<input class="form-control" formControlName="email" title="Please enter your email" placeholder="[email protected]">
<p class="help-block" *ngIf="signUpForm.get('email').hasError('required') && signUpForm.get('email').touched">La dirección de email es obligatoria</p>
<p class="help-block" *ngIf="signUpForm.get('email').hasError('email') && signUpForm.get('email').touched">Debe ingresar una dirección de correo válida</p>
</div>
<div class="form-group">
<label for="password" class="control-label">Contrase?a:</label>
<input type="password" class="form-control" formControlName="password" title="Please enter your password" [(ngModel)]="password">
<p class="help-block" *ngIf="signUpForm.get('password').hasError('required') && signUpForm.get('password').touched">Debe ingresar una contrase?a</p>
</div>
<div class="form-group">
<label for="confirmedPassword" class="control-label">Confirmar Contrase?a:</label>
<input type="password" class="form-control" formControlName="confirmedPassword" title="Please re-enter your password" [(ngModel)]="confirmedPassword">
<p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('required') && signUpForm.get('confirmedPassword').touched">La confirmación de contrase?a no puede estar vacía</p>
<p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('passwordMismatch') && signUpForm.get('confirmedPassword').touched">Las contrase?as no coinciden</p>
</div>
<button type="submit" class="btn btn-success" [disabled]="!signUpForm.valid">Registrarse</button>
<a routerLink="/signin" class="btn btn-default" style="">Ya tenes usuario? Logueate</a> {{ creationMessage }}
</form>
</div>
</div>
</div>
signup.component.ts
注册.component.ts
import { Component, OnInit, ViewChild, Input } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { CustomValidators } from '../../shared/custom-validators';
import { Observable } from 'rxjs/Observable';
@Component({
selector: 'app-signup',
templateUrl: './signup.component.html',
styleUrls: ['./signup.component.sass']
})
export class SignupComponent implements OnInit {
signUpForm: FormGroup;
user = {
username: '',
email: '',
password: ''
};
submitted = false;
@Input() password='';
@Input() confirmedPassword='';
constructor() { }
ngOnInit() {
this.signUpForm = new FormGroup({
'username': new FormControl(null, [Validators.required, Validators.minLength(6), Validators.maxLength(15)]),
'email': new FormControl(null, [Validators.required, Validators.email, Validators.minLength(5)]),
'password': new FormControl(null, [Validators.required]),
'confirmedPassword': new FormControl(null, [Validators.required, CustomValidators.passwordsMatch(this.password,this.confirmedPassword).bind(this)])
});
}
onSubmit() {
if (this.signUpForm.valid) {
console.log(this.signUpForm.value);
}
}
}
custom-validators.ts
自定义validators.ts
import { FormControl } from '@angular/forms';
export class CustomValidators{
public static passwordsMatch(password: string, confirmedPassword: string) {
return (control: FormControl) : { [s: string]: boolean } =>{
//getting undefined values for both variables
console.log(password,confirmedPassword);
//if I change this condition to === it throws the error if the
// two fields are the same, so this part works
if (password !== confirmedPassword) {
return { 'passwordMismatch': true }
} else {
//it always gets here no matter what
return null;
}
}
}
}
回答by Shailesh Ladumor
import {AbstractControl, FormBuilder, FormGroup, Validators} from
导入 {AbstractControl, FormBuilder, FormGroup, Validators} from
set your password input into the group and no need to use "ngModel".
将您的密码输入组设置,无需使用“ngModel”。
<div class="form-group row" formGroupName="passwords">
<div class="form-group">
<label for="password" class="control-label">Contrase?a:</label>
<input type="password" class="form-control" formControlName="password" title="Please enter your password">
<p class="help-block" *ngIf="signUpForm.get('password').hasError('required') && signUpForm.get('password').touched">Debe ingresar una contrase?a</p>
</div>
<div class="form-group">
<label for="confirmedPassword" class="control-label">Confirmar Contrase?a:</label>
<input type="password" class="form-control" formControlName="confirmedPassword" title="Please re-enter your password">
<p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('required') && signUpForm.get('confirmedPassword').touched">Password must be required</p>
<p class="help-block" *ngIf="signUpForm.get('confirmedPassword').hasError('passwordMismatch') && signUpForm.get('confirmedPassword').touched">password does not match</p>
</div>
buildForm(): void {
this.userForm = this.formBuilder.group({
passwords: this.formBuilder.group({
password: ['', [Validators.required]],
confirm_password: ['', [Validators.required]],
}, {validator: this.passwordConfirming}),
});
}
add this custom function for validate password and confirm password
添加此自定义功能以验证密码和确认密码
passwordConfirming(c: AbstractControl): { invalid: boolean } {
if (c.get('password').value !== c.get('confirm_password').value) {
return {invalid: true};
}
}
Display error when password does not match
密码不匹配时显示错误
<div style='color:#ff7355' *ngIf="userForm.get(['passwords','password']).value != userForm.get(['passwords','confirm_password']).value && userForm.get(['passwords','confirm_password']).value != null">
Password does not match</div>
回答by Daniel Orme?o
The issue is that you are mixing the reactive forms module with the input approach. This is causing you to get undefinedwhen passing the values to the validator.
问题是您将反应形式模块与输入方法混合在一起。这导致您undefined在将值传递给验证器时获取。
You don't need to bind to the ng-modelwhen using the reactive forms. Instead, you should access the value of the fields from the Instance of FormGroup.
ng-model使用反应式形式时,您不需要绑定到。相反,您应该从 的 Instance 访问字段的值FormGroup。
I do something like this in an app to validate the passwords match.
我在应用程序中执行类似操作以验证密码匹配。
public Credentials: FormGroup;
ngOnInit() {
this.Credentials = new FormGroup({});
this.Credentials.addControl('Password', new FormControl('', [Validators.required]));
this.Credentials.addControl('Confirmation', new FormControl(
'', [Validators.compose(
[Validators.required, this.validateAreEqual.bind(this)]
)]
));
}
private validateAreEqual(fieldControl: FormControl) {
return fieldControl.value === this.Credentials.get("Password").value ? null : {
NotEqual: true
};
}
Note that the validator expects a FormControlfield as a parameter and it compares the value of the field to that of the value of the Passwordfield of the CredentialsFormGroup.
请注意,验证器需要一个FormControl字段作为参数,并将该字段的值Password与CredentialsFormGroup.
In the HTMLmake sure to remove the ng-model.
在HTML确保删除ng-model.
<input type="password" class="form-control" formControlName="confirmedPassword" title="Please re-enter your password" >
<!-- AND -->
<input type="password" class="form-control" formControlName="password" title="Please enter your password">
Hope this helps!
希望这可以帮助!
回答by Yang Zhang
There are two types of validators: FormGroup validatorand FormControl validator. To verify two passwords match, you have to add a FormGroup validator. Below is my example:
有两种类型的验证器:FormGroup 验证器和FormControl 验证器。要验证两个密码是否匹配,您必须添加一个 FormGroup 验证器。下面是我的例子:
Note: this.fb is the injected FormBuilder
注意:this.fb 是注入的 FormBuilder
this.newAccountForm = this.fb.group(
{
newPassword: ['', [Validators.required, Validators.minLength(6)]],
repeatNewPassword: ['', [Validators.required, Validators.minLength(6)]],
},
{validator: this.passwordMatchValidator}
);
passwordMatchValidator(frm: FormGroup) {
return frm.controls['newPassword'].value === frm.controls['repeatNewPassword'].value ? null : {'mismatch': true};
}
and in the templeate:
并在圣殿中:
<div class="invalid-feedback" *ngIf="newAccountForm.errors?.mismatch && (newAccountForm.controls['repeatNewPassword'].dirty || newAccountForm.controls['repeatNewPassword'].touched)">
Passwords don't match.
</div>
The key pointhere is to add the FormGroup validator as the second parameterto the group method.
这里的关键点是将 FormGroup 验证器作为第二个参数添加到 group 方法中。
回答by Raja Rama Mohan Thavalam
Please update FormGroup code like below in Angular5
请在 Angular5 中更新如下所示的 FormGroup 代码
this.signUpForm = new FormGroup({
'username': new FormControl(null, [Validators.required, Validators.minLength(6), Validators.maxLength(15)]),
'email': new FormControl(null, [Validators.required, Validators.email, Validators.minLength(5)]),
'password': new FormControl(null, [Validators.required]),
'confirmedPassword': new FormControl(null, [Validators.required])
}, this.pwdMatchValidator);
Add pwdMatchValidatorfunction in your component
pwdMatchValidator在您的组件中添加功能
pwdMatchValidator(frm: FormGroup) {
return frm.get('password').value === frm.get('confirmedPassword').value
? null : {'mismatch': true};
}
Add validation message in your template
在模板中添加验证消息
<span *ngIf="confirmedPassword.errors || signUpForm .errors?.mismatch">
Password doesn't match
</span>
Please find the below angular material working component.
请找到下面的角材料工作部件。
Component Templete Code password.component.html
组件模板代码 password.component.html
<form class="cahnge-pwd-form" (ngSubmit)="onSubmit()" name="passwordForm" [formGroup]="passwordForm" #formDir="ngForm">
<div fxLayout='column'>
<mat-form-field>
<input matInput name="password" placeholder="Password" [type]="hide ? 'text' : 'password'" formControlName="password" required>
<mat-icon matSuffix (click)="hide = !hide">{{hide ? 'visibility_off' : 'visibility'}}</mat-icon>
<mat-error *ngIf="password.invalid && (password.dirty || password.touched || isSubmit)">
<span *ngIf="password.errors.required">
Please enter a Password.
</span>
<span *ngIf="password.errors.maxlength">
Please enter a Email no more than 16 characters.
</span>
<span *ngIf="password.errors.minlength">
Please enter a password at least 6 characters.
</span>
</mat-error>
</mat-form-field>
<mat-form-field>
<input matInput name="password" placeholder="Confirm Password" [type]="confirm_hide ? 'text' : 'password'" formControlName="confirm_password"
required>
<mat-icon matSuffix (click)="confirm_hide = !confirm_hide">{{confirm_hide ? 'visibility_off' : 'visibility'}}</mat-icon>
<mat-error *ngIf="(confirm_password.invalid && (confirm_password.dirty || confirm_password.touched || isSubmit) || passwordForm.errors?.mismatch)">
<span *ngIf="confirm_password.errors || passwordForm.errors?.mismatch">
Password doesn't match
</span>
</mat-error>
</mat-form-field>
<div fxLayout='row' fxLayoutGap="10px">
<button type="submit" mat-raised-button color="primary">Submit</button>
<button type="button" (click)="formDir.resetForm(passwordForm)" mat-raised-button color="warn">Cancel</button>
</div>
</div>
</form>
Component Code : password.component.ts
组件代码: password.component.ts
import { Component, OnInit, AfterViewInit } from '@angular/core';
import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { PasswordService } from './password.service';
import { PasswordValidation } from './confirm';
@Component({
selector: 'app-password',
templateUrl: './password.component.html',
styleUrls: ['./password.component.css']
})
export class PasswordComponent implements OnInit {
passwordForm: FormGroup;
isSubmit: boolean;
constructor(private router: Router, private passwordService: PasswordService, private toastrService: ToastrService, private route: ActivatedRoute) { }
ngOnInit() {
this.passwordForm = new FormGroup({
'password': new FormControl('', [
Validators.required,
Validators.minLength(6),
Validators.maxLength(16),
]),
'confirm_password': new FormControl('', [
Validators.required,
Validators.minLength(6),
Validators.maxLength(16),
]),
}, this.pwdMatchValidator);
}
pwdMatchValidator(frm: FormGroup) {
return frm.get('password').value === frm.get('confirm_password').value
? null : {'mismatch': true};
}
get password() { return this.passwordForm.get('password'); }
get confirm_password() { return this.passwordForm.get('confirm_password'); }
onSubmit(formvalue):boolean {
this.isSubmit = true;
if (this.passwordForm.invalid) {
return false;
} else {
this.passwordService.updatePassword(this.passwordForm.value)
.subscribe((res) => {
if (res.status == 'success') {
this.toastrService.success(res.msg);
this.router.navigate(['/change-password']);
}
})
return true;
}
}
}
回答by Dmitry Grinko
this.myForm = this.fb.group({
userEmail: [null, [Validators.required, Validators.email]],
pwd: [null, [Validators.required, Validators.minLength(8)]],
pwdConfirm: [null, [Validators.required]],
}, {validator: this.pwdConfirming('pwd', 'pwdConfirm')});
pwdConfirming(key: string, confirmationKey: string) {
return (group: FormGroup) => {
const input = group.controls[key];
const confirmationInput = group.controls[confirmationKey];
return confirmationInput.setErrors(
input.value !== confirmationInput.value ? {notEquivalent: true} : null
);
};
}
回答by grigson
When you need to validate on more than one field, and you wish to declare validator at form creation time, FormGroup validatormust be used. The main issue with form validator is that it attaches error to form and not to validating control, which leeds to some inconsistents in template. Here is reusable form validator wich attaches error to both form and control
当您需要对多个字段进行验证,并且希望在创建表单时声明验证器时,必须使用FormGroup 验证器。表单验证器的主要问题是它将错误附加到表单而不是验证控件,这导致模板中的一些不一致。这是可重用的表单验证器,它将错误附加到表单和控件
// in validators.ts file
export function controlsEqual(
controlName: string,
equalToName: string,
errorKey: string = controlName // here you can customize validation error key
) {
return (form: FormGroup) => {
const control = form.get(controlName);
if (control.value !== form.get(equalToName).value) {
control.setErrors({ [errorKey]: true });
return {
[errorKey]: true
}
} else {
control.setErrors(null);
return null
}
}
}
// then you can use it like
ngOnInit() {
this.vmForm = this.fb.group({
username: ['', [Validators.required, Validators.email]],
password: ['', [
Validators.required,
Validators.pattern('[\w\d]+'),
Validators.minLength(8)]],
confirm: [''], // no need for any validators here
}, {
// here we attach our form validator
validators: controlsEqual('confirm', 'password')
});
}
回答by Bernardo Mondragón Brozon
I would do the same as Shailesh Ladumorbut adding the following line before returning in the validation function:
我会和Shailesh Ladumor做同样的事情,但在返回验证函数之前添加以下行:
c.get('confirm_password').setErrors({'noMatch': true});
So that the validation function looks like this:
这样验证函数看起来像这样:
passwordConfirming(c: AbstractControl): { invalid: boolean } {
if (c.get('password').value !== c.get('confirm_password').value) {
c.get('confirm_password').setErrors({'noMatch': true});
return {invalid: true};
}
}
This will not only set the hole userFormas an invalid form group, but it will also set confirm_passwordas an invalid form control.
这不仅会将孔设置userForm为无效的表单组,还会将其设置confirm_password为无效的表单控件。
With this you can later call the following function in your template:
有了这个,您以后可以在模板中调用以下函数:
public getPasswordConfirmationErrorMessage() {
if (this.userForm.get('confirm_password').hasError('required')) {
return 'You must retype your password';
} else if (this.userForm.get('confirm_password').hasError('noMatch')) {
return 'Passwords do not match';
} else {
return '';
}
}
}
回答by Robby Cornelissen
When you're creating the validator, you're passing in the values of passwordand confirmedPassword, but changes in those values will not be reflected in the validator.
当您创建验证器时,您传递了password和的值confirmedPassword,但这些值的更改不会反映在验证器中。
The two options I see are:
我看到的两个选项是:
- define your validator on the
FormGroup, and look up the values from the two controls you want to compare; or - since you're binding to
thisalready, usethis.passwordandthis.confirmedPasswordin your validator.
- 在 上定义验证器
FormGroup,并从要比较的两个控件中查找值;或者 - 因为你已经绑定
this了,所以在你的验证器中使用this.password和this.confirmedPassword。
回答by Anup Kattel
Just for the variety, I'm adding one more way to do this. Basically, I created a simple custom validator that takes the original control (first entered field) and checks it's value with the re-entry control (second control).
只是为了多样性,我添加了另一种方法来做到这一点。基本上,我创建了一个简单的自定义验证器,它采用原始控件(第一个输入的字段)并使用重新输入控件(第二个控件)检查它的值。
import { AbstractControl, ValidatorFn } from "@angular/forms";
export abstract class ReEnterValidation {
static reEnterValidation(originalControl: AbstractControl): ValidatorFn {
return (control: AbstractControl): { [s: string]: boolean } => {
if (control.value != originalControl.value) {
return { 'reentry': true };
}
};
}
}
You can either set this validator initially when creating a new form control:
您可以在创建新表单控件时最初设置此验证器:
control1 = new FormControl('', ReEnterValidation.reEnterValidation(control2));
Or, you can set it afterwards:
或者,您可以在之后进行设置:
control.setValidators(ReEnterValidation.reEnterValidation(this._newPinControl));
control.updateValueAndValidity();
In the view, you can show the errors as following:
在视图中,您可以显示如下错误:
<!-- Confirm pin validation -->
<div *ngIf="control2.invalid && (control2.dirty || control2.touched)">
<div *ngIf="control2.errors.reentry">
The re-entered password doesn't match. Please try again.
</div>
</div>

