密码和确认密码字段验证 angular2 反应形式
password and confirm password field validation angular2 reactive forms
我需要使用响应式 angular2 检查密码和确认密码字段是否具有相同的值。我确实在这里看到了很多相同的答案, ,,但是 none 似乎适用于 me.Can 有人请帮忙。"this" 在我的验证函数中未定义:( .
分享我的代码,
this.addEditUserForm = this.builder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
title: ['', Validators.required],
email: ['', Validators.required],
password: ['', Validators.required],
confirmPass: ['', [Validators.required, this.validatePasswordConfirmation]]
});
validatePasswordConfirmation(group: FormGroup): any{
let valid = true;
// if (this.addEditUserForm.controls.password != this.addEditUserForm.controls.confirmPass) {
// valid = false;
// this.addEditUserForm.controls.confirmPass.setErrors({validatePasswordConfirmation: true});
// }
return valid;
}
如果你想那样做,你需要将函数绑定到当前的 "this" 上下文。
传递 this.validatePasswordConfirmation.bind(this)
但请注意,此函数将传递给 FormControl 进行确认,而不是像您在函数签名中声明的那样传递给 FormGroup。
最好在表单组中有一个嵌套组,我们有一个自定义验证器使用 password
和 confirmPass
检查表单组,因此当任一字段发生更改时,验证器被触发,因为之前它只在 confirmPass
字段被修改时触发。
所以改为在外部表单组中做这样的事情:
// ...
passwords: this.fb.group({
password: ['', [...]],
confirmPass: ['', [...]]
}, {validators: this.checkPasswords}) // add a validator for the whole group
// ...
然后验证器可能如下所示:
checkPasswords: ValidatorFn = (group: AbstractControl): ValidationErrors | null => {
let pass = group.get('password').value;
let confirmPass = group.get('confirmPassword').value
return pass === confirmPass ? null : { notSame: true }
}
然后可以这样显示验证错误:
*ngIf="addEditUserForm.hasError('notSame', 'passwords')"
当然您不需要嵌套组,但最好不要在每次表单发生任何更改时都触发自定义验证器。这样只有当这个内部表单组发生变化时它才会被触发。
这就是最终对我有用的 -
this.addEditUserForm = this.builder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
title: ['', Validators.required],
email: ['', Validators.required],
password: ['', Validators.required],
confirmPass: ['', Validators.required]
},{validator: this.checkIfMatchingPasswords('password', 'confirmPass')});
checkIfMatchingPasswords(passwordKey: string, passwordConfirmationKey: string) {
return (group: FormGroup) => {
let passwordInput = group.controls[passwordKey],
passwordConfirmationInput = group.controls[passwordConfirmationKey];
if (passwordInput.value !== passwordConfirmationInput.value) {
return passwordConfirmationInput.setErrors({notEquivalent: true})
}
else {
return passwordConfirmationInput.setErrors(null);
}
}
}
我采用了一种适用于任何控件的不同方法。首先我定义了窗体的基本控件:
this.myForm = this.formBuilder.group({
name: ['', Validators.required],
password: ['', Validators.required],
});
然后我创建一个新控件以使用我的自定义验证器确认该值:
const confirmPasswordControl = new FormControl('', {
validator: sameValueAs(this.myForm, 'password')
});
this.myForm.addControl('confirmPassword', confirmPasswordControl);
sameValueAs
验证器的代码如下,您可以将其定义在一个单独的文件中,以便在任何地方使用
export function sameValueAs(group: FormGroup, controlName: string): ValidatorFn {
return (control: FormControl) => {
const myValue = control.value;
const compareValue = group.controls[controlName].value;
return (myValue === compareValue) ? null : {valueDifferentFrom:controlName};
};
}
如果您不想通过自定义验证器,您可以只创建一个独立的输入字段,因此不会在您的 formGroup 中计算,而是通过 ngModel
<input type="password" matInput [(ngModel)]="passwordConfirm" [ngModelOptions]="{standalone: true}">
然后在您的 ts 中,您可以根据需要验证并抛出错误或使表单无效。刚刚发现它稍微快捷实用:
// 检查密码匹配
if (this.staffAccountForm.value.password !== this.passwordConfirm) {
this.snackbar.snackBarSimple('Passwords do not match.');
return false;
}
对于那些想要添加自定义验证器而不被强制通过表单组验证的人,可以在定义表单后添加验证器。
这种方法的一个优点是错误被添加到表单控件而不是表单组。这样更容易显示与字段关联的错误,因为我们可以直接在 field/form 控件本身上检查错误。
我是这样实现的:
自定义验证器
import { AbstractControl, ValidatorFn } from '@angular/forms';
export class MismatchValidator {
static mismatch(otherInputControl: AbstractControl): ValidatorFn {
return (inputControl: AbstractControl): { [key: string]: boolean } | null => {
if (inputControl.value !== undefined
&& inputControl.value.trim() != ""
&& inputControl.value !== otherInputControl.value) {
return { 'mismatch': true };
}
return null;
};
}
}
将自定义验证器应用于表单控件
ngOnInit() {
this.initForm();
// The validators are set after defining the form in order to be able to access the password control and pass it to the custom validator as a parameter
this.setValidators();
}
private initForm() {
this.myForm = this.formBuilder.group({
password: new FormControl(''),
passwordConfirmation: new FormControl('')
});
}
private setValidators() {
const formValidators = {
"password": Validators.compose([
Validators.required,
//....
]),
"passwordConfirmation": Validators.compose([
Validators.required,
MismatchValidator.mismatch(this.myForm.get("password"))
])
}
this.passwordRecoveryForm.get("password").setValidators(
formValidators["password"]
);
this.passwordRecoveryForm.get("passwordConfirmation").setValidators(
formValidators["passwordConfirmation"]
);
}
在定义表单后设置验证器,以便能够访问密码控件并将其作为参数传递给自定义验证器。
我在实现这个时遇到了一些问题,当我用自定义验证器和 errorStateMatcher 实现它时,我遇到了 formbuilder.group 函数被弃用的问题,但经过一些检查后我发现我的验证器有更改以符合组功能。
控制器看起来像这样:
// ...
addEditUserForm: FormGroup;
passwordMatcher = new ComparisonErrorStateMatcher();
constructor(private formBuilder: FormBuilder) {
this.addEditUserForm = this.formBuilder.group({
password: ['', Validators.required],
confirmPass: ['', Validators.required],
}, { validators: [MatchValidator.validate] }); // add validator to group
}
// ...
我的验证器看起来像这样:
export class MatchValidator {
// (group: AbstractControl) is the form group but needs to be AbstractControl instead of (group: FormGroup) to remove deprecation warning.
static validate(group: AbstractControl): ValidationErrors | null {
const password = group.get('password')?.value;
const confirmPassword = group.get('confirmPass')?.value;
return password === confirmPass ? null : { notMatching: true }
};
}
我的 ErrorStateMatcher 看起来像这样:
export class ComparisonErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const invalidCtrl = !!(control && control.invalid && control.parent?.dirty);
const invalidParent = !!(control && control.parent && control.parent.invalid && control.parent.dirty);
return (invalidCtrl || invalidParent) && (control?.touched ?? false);
}
}
最后 HTML 必须看起来像这样:
<form [formGroup]="addEditUserForm">
<mat-form-field >
<mat-label>password</mat-label>
<input formControlName="password"
matInput />
<mat-error *ngIf="newPasswordForm.hasError('required')">
password is required
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>confirm password</mat-label>
<input formControlName="confirmPass"
[errorStateMatcher]="passwordMatcher"
matInput />
<mat-error *ngIf="newPasswordForm.hasError('notMatching')">
passwords don't match
</mat-error>
</mat-form-field>
</form>
这将创建一个表单,其中包含两个需要匹配的输入字段。
您的回答应该没问题。您需要做的就是添加 .value
点赞:
this.addEditUserForm = this.builder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
title: ['', Validators.required],
email: ['', Validators.required],
password: ['', Validators.required],
confirmPass: ['', [Validators.required, this.validatePasswordConfirmation]]
});
validatePasswordConfirmation(group: FormGroup): any{
let valid = true;
if (this.addEditUserForm.controls.password**.value** != this.addEditUserForm.controls.confirmPass**.value**) {
valid = false;
this.addEditUserForm.controls.confirmPass.setErrors({validatePasswordConfirmation: true});
// }
return valid;
}
使用响应式表单 - 我认为这是简单的方法
变化-password.ts
passwordChangeForm = new FormGroup(
{
currentPassword: new FormControl("", [
Validators.required,
Validators.minLength(6),
]),
newPassword: new FormControl("", [
Validators.required,
Validators.minLength(6),
]),
confirmNewPassword: new FormControl("", [
Validators.required,
Validators.minLength(6),
]),
},
{
validators: (control) => {
if (control.value.newPassword !== control.value.confirmNewPassword) {
control.get("confirmNewPassword").setErrors({ notSame: true });
}
return null;
},
}
);
变化-password.html
<div>
<h1 mat-dialog-title>Change Password</h1>
<form [formGroup]="passwordChangeForm">
<mat-form-field appearance="outline">
<mat-label>Current Password</mat-label>
<input matInput formControlName="currentPassword" type="password" />
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>New Password</mat-label>
<input matInput formControlName="newPassword" type="password" />
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Confirm New Password</mat-label>
<input matInput formControlName="confirmNewPassword" type="password" />
<mat-error
*ngIf="passwordChangeForm.get('confirmNewPassword').hasError('notSame')"
>
New Password Doesn't match
</mat-error>
</mat-form-field>
</form>
<button
mat-raised-button
color="primary"
(click)="changePassword()"
[disabled]="passwordChangeForm.invalid"
>
Change Password
</button>
</div>
这是我使用的匹配验证器:
export function matchValidator(
matchTo: string,
reverse?: boolean
): ValidatorFn {
return (control: AbstractControl):
ValidationErrors | null => {
if (control.parent && reverse) {
const c = (control.parent?.controls as any)[matchTo]
as AbstractControl;
if (c) {
c.updateValueAndValidity();
}
return null;
}
return !!control.parent &&
!!control.parent.value &&
control.value ===
(control.parent?.controls as any)[matchTo].value
? null
: { matching: true };
};
}
你可以像这样使用它:
password: ['', [
Validators.required,
Validators.pattern('^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$'),
Validators.minLength(6),
Validators.maxLength(25),
matchValidator('confirmPassword', true)
]],
confirmPassword: ['', [
Validators.required,
matchValidator('password')
]],
它只会在 confirmPassword
上显示错误消息,但会在两个字段上进行检查。
<mat-error *ngIf="confirmPassword.hasError('matching')">
Password must match.
</mat-error>
有关详细信息,请参阅 here。
J
Angular 12更新:
由于上述解决方案对我不起作用,这里是 angular 12
的密码匹配验证的实现
Custom validator
export function mustMatch(controlName: string, matchingControlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
const matchingControl = formGroup.controls[matchingControlName];
if (matchingControl.errors && !matchingControl.errors.mustMatch) {
return;
}
// set error on matchingControl if validation fails
if (control.value !== matchingControl.value) {
matchingControl.setErrors({ mustMatch: true });
} else {
matchingControl.setErrors(null);
}
return null;
};
}
component.ts
initPasswordForm() {
this.passwordForm = new FormGroup({
password: new FormControl(null, [
Validators.required,
Validators.minLength(6)
]),
passwordConfirmation: new FormControl(null, [
Validators.required,
Validators.minLength(6),
]),
},
mustMatch('password', 'passwordConfirmation')
);
}
components.html
<span *ngIf="passwordForm.get('passwordConfirmation').errors?.'mustMatch']"> The password confirmation does not match the entered password</span>
我需要使用响应式 angular2 检查密码和确认密码字段是否具有相同的值。我确实在这里看到了很多相同的答案,
this.addEditUserForm = this.builder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
title: ['', Validators.required],
email: ['', Validators.required],
password: ['', Validators.required],
confirmPass: ['', [Validators.required, this.validatePasswordConfirmation]]
});
validatePasswordConfirmation(group: FormGroup): any{
let valid = true;
// if (this.addEditUserForm.controls.password != this.addEditUserForm.controls.confirmPass) {
// valid = false;
// this.addEditUserForm.controls.confirmPass.setErrors({validatePasswordConfirmation: true});
// }
return valid;
}
如果你想那样做,你需要将函数绑定到当前的 "this" 上下文。
传递 this.validatePasswordConfirmation.bind(this)
但请注意,此函数将传递给 FormControl 进行确认,而不是像您在函数签名中声明的那样传递给 FormGroup。
最好在表单组中有一个嵌套组,我们有一个自定义验证器使用 password
和 confirmPass
检查表单组,因此当任一字段发生更改时,验证器被触发,因为之前它只在 confirmPass
字段被修改时触发。
所以改为在外部表单组中做这样的事情:
// ...
passwords: this.fb.group({
password: ['', [...]],
confirmPass: ['', [...]]
}, {validators: this.checkPasswords}) // add a validator for the whole group
// ...
然后验证器可能如下所示:
checkPasswords: ValidatorFn = (group: AbstractControl): ValidationErrors | null => {
let pass = group.get('password').value;
let confirmPass = group.get('confirmPassword').value
return pass === confirmPass ? null : { notSame: true }
}
然后可以这样显示验证错误:
*ngIf="addEditUserForm.hasError('notSame', 'passwords')"
当然您不需要嵌套组,但最好不要在每次表单发生任何更改时都触发自定义验证器。这样只有当这个内部表单组发生变化时它才会被触发。
这就是最终对我有用的 -
this.addEditUserForm = this.builder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
title: ['', Validators.required],
email: ['', Validators.required],
password: ['', Validators.required],
confirmPass: ['', Validators.required]
},{validator: this.checkIfMatchingPasswords('password', 'confirmPass')});
checkIfMatchingPasswords(passwordKey: string, passwordConfirmationKey: string) {
return (group: FormGroup) => {
let passwordInput = group.controls[passwordKey],
passwordConfirmationInput = group.controls[passwordConfirmationKey];
if (passwordInput.value !== passwordConfirmationInput.value) {
return passwordConfirmationInput.setErrors({notEquivalent: true})
}
else {
return passwordConfirmationInput.setErrors(null);
}
}
}
我采用了一种适用于任何控件的不同方法。首先我定义了窗体的基本控件:
this.myForm = this.formBuilder.group({
name: ['', Validators.required],
password: ['', Validators.required],
});
然后我创建一个新控件以使用我的自定义验证器确认该值:
const confirmPasswordControl = new FormControl('', {
validator: sameValueAs(this.myForm, 'password')
});
this.myForm.addControl('confirmPassword', confirmPasswordControl);
sameValueAs
验证器的代码如下,您可以将其定义在一个单独的文件中,以便在任何地方使用
export function sameValueAs(group: FormGroup, controlName: string): ValidatorFn {
return (control: FormControl) => {
const myValue = control.value;
const compareValue = group.controls[controlName].value;
return (myValue === compareValue) ? null : {valueDifferentFrom:controlName};
};
}
如果您不想通过自定义验证器,您可以只创建一个独立的输入字段,因此不会在您的 formGroup 中计算,而是通过 ngModel
<input type="password" matInput [(ngModel)]="passwordConfirm" [ngModelOptions]="{standalone: true}">
然后在您的 ts 中,您可以根据需要验证并抛出错误或使表单无效。刚刚发现它稍微快捷实用:
// 检查密码匹配
if (this.staffAccountForm.value.password !== this.passwordConfirm) {
this.snackbar.snackBarSimple('Passwords do not match.');
return false;
}
对于那些想要添加自定义验证器而不被强制通过表单组验证的人,可以在定义表单后添加验证器。
这种方法的一个优点是错误被添加到表单控件而不是表单组。这样更容易显示与字段关联的错误,因为我们可以直接在 field/form 控件本身上检查错误。
我是这样实现的:
自定义验证器
import { AbstractControl, ValidatorFn } from '@angular/forms';
export class MismatchValidator {
static mismatch(otherInputControl: AbstractControl): ValidatorFn {
return (inputControl: AbstractControl): { [key: string]: boolean } | null => {
if (inputControl.value !== undefined
&& inputControl.value.trim() != ""
&& inputControl.value !== otherInputControl.value) {
return { 'mismatch': true };
}
return null;
};
}
}
将自定义验证器应用于表单控件
ngOnInit() {
this.initForm();
// The validators are set after defining the form in order to be able to access the password control and pass it to the custom validator as a parameter
this.setValidators();
}
private initForm() {
this.myForm = this.formBuilder.group({
password: new FormControl(''),
passwordConfirmation: new FormControl('')
});
}
private setValidators() {
const formValidators = {
"password": Validators.compose([
Validators.required,
//....
]),
"passwordConfirmation": Validators.compose([
Validators.required,
MismatchValidator.mismatch(this.myForm.get("password"))
])
}
this.passwordRecoveryForm.get("password").setValidators(
formValidators["password"]
);
this.passwordRecoveryForm.get("passwordConfirmation").setValidators(
formValidators["passwordConfirmation"]
);
}
在定义表单后设置验证器,以便能够访问密码控件并将其作为参数传递给自定义验证器。
我在实现这个时遇到了一些问题,当我用自定义验证器和 errorStateMatcher 实现它时,我遇到了 formbuilder.group 函数被弃用的问题,但经过一些检查后我发现我的验证器有更改以符合组功能。
控制器看起来像这样:
// ...
addEditUserForm: FormGroup;
passwordMatcher = new ComparisonErrorStateMatcher();
constructor(private formBuilder: FormBuilder) {
this.addEditUserForm = this.formBuilder.group({
password: ['', Validators.required],
confirmPass: ['', Validators.required],
}, { validators: [MatchValidator.validate] }); // add validator to group
}
// ...
我的验证器看起来像这样:
export class MatchValidator {
// (group: AbstractControl) is the form group but needs to be AbstractControl instead of (group: FormGroup) to remove deprecation warning.
static validate(group: AbstractControl): ValidationErrors | null {
const password = group.get('password')?.value;
const confirmPassword = group.get('confirmPass')?.value;
return password === confirmPass ? null : { notMatching: true }
};
}
我的 ErrorStateMatcher 看起来像这样:
export class ComparisonErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const invalidCtrl = !!(control && control.invalid && control.parent?.dirty);
const invalidParent = !!(control && control.parent && control.parent.invalid && control.parent.dirty);
return (invalidCtrl || invalidParent) && (control?.touched ?? false);
}
}
最后 HTML 必须看起来像这样:
<form [formGroup]="addEditUserForm">
<mat-form-field >
<mat-label>password</mat-label>
<input formControlName="password"
matInput />
<mat-error *ngIf="newPasswordForm.hasError('required')">
password is required
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>confirm password</mat-label>
<input formControlName="confirmPass"
[errorStateMatcher]="passwordMatcher"
matInput />
<mat-error *ngIf="newPasswordForm.hasError('notMatching')">
passwords don't match
</mat-error>
</mat-form-field>
</form>
这将创建一个表单,其中包含两个需要匹配的输入字段。
您的回答应该没问题。您需要做的就是添加 .value
点赞:
this.addEditUserForm = this.builder.group({
firstName: ['', Validators.required],
lastName: ['', Validators.required],
title: ['', Validators.required],
email: ['', Validators.required],
password: ['', Validators.required],
confirmPass: ['', [Validators.required, this.validatePasswordConfirmation]]
});
validatePasswordConfirmation(group: FormGroup): any{
let valid = true;
if (this.addEditUserForm.controls.password**.value** != this.addEditUserForm.controls.confirmPass**.value**) {
valid = false;
this.addEditUserForm.controls.confirmPass.setErrors({validatePasswordConfirmation: true});
// }
return valid;
}
使用响应式表单 - 我认为这是简单的方法
变化-password.ts
passwordChangeForm = new FormGroup(
{
currentPassword: new FormControl("", [
Validators.required,
Validators.minLength(6),
]),
newPassword: new FormControl("", [
Validators.required,
Validators.minLength(6),
]),
confirmNewPassword: new FormControl("", [
Validators.required,
Validators.minLength(6),
]),
},
{
validators: (control) => {
if (control.value.newPassword !== control.value.confirmNewPassword) {
control.get("confirmNewPassword").setErrors({ notSame: true });
}
return null;
},
}
);
变化-password.html
<div>
<h1 mat-dialog-title>Change Password</h1>
<form [formGroup]="passwordChangeForm">
<mat-form-field appearance="outline">
<mat-label>Current Password</mat-label>
<input matInput formControlName="currentPassword" type="password" />
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>New Password</mat-label>
<input matInput formControlName="newPassword" type="password" />
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Confirm New Password</mat-label>
<input matInput formControlName="confirmNewPassword" type="password" />
<mat-error
*ngIf="passwordChangeForm.get('confirmNewPassword').hasError('notSame')"
>
New Password Doesn't match
</mat-error>
</mat-form-field>
</form>
<button
mat-raised-button
color="primary"
(click)="changePassword()"
[disabled]="passwordChangeForm.invalid"
>
Change Password
</button>
</div>
这是我使用的匹配验证器:
export function matchValidator(
matchTo: string,
reverse?: boolean
): ValidatorFn {
return (control: AbstractControl):
ValidationErrors | null => {
if (control.parent && reverse) {
const c = (control.parent?.controls as any)[matchTo]
as AbstractControl;
if (c) {
c.updateValueAndValidity();
}
return null;
}
return !!control.parent &&
!!control.parent.value &&
control.value ===
(control.parent?.controls as any)[matchTo].value
? null
: { matching: true };
};
}
你可以像这样使用它:
password: ['', [
Validators.required,
Validators.pattern('^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]+)$'),
Validators.minLength(6),
Validators.maxLength(25),
matchValidator('confirmPassword', true)
]],
confirmPassword: ['', [
Validators.required,
matchValidator('password')
]],
它只会在 confirmPassword
上显示错误消息,但会在两个字段上进行检查。
<mat-error *ngIf="confirmPassword.hasError('matching')">
Password must match.
</mat-error>
有关详细信息,请参阅 here。
J
Angular 12更新:
由于上述解决方案对我不起作用,这里是 angular 12
的密码匹配验证的实现Custom validator
export function mustMatch(controlName: string, matchingControlName: string) {
return (formGroup: FormGroup) => {
const control = formGroup.controls[controlName];
const matchingControl = formGroup.controls[matchingControlName];
if (matchingControl.errors && !matchingControl.errors.mustMatch) {
return;
}
// set error on matchingControl if validation fails
if (control.value !== matchingControl.value) {
matchingControl.setErrors({ mustMatch: true });
} else {
matchingControl.setErrors(null);
}
return null;
};
}
component.ts
initPasswordForm() {
this.passwordForm = new FormGroup({
password: new FormControl(null, [
Validators.required,
Validators.minLength(6)
]),
passwordConfirmation: new FormControl(null, [
Validators.required,
Validators.minLength(6),
]),
},
mustMatch('password', 'passwordConfirmation')
);
}
components.html
<span *ngIf="passwordForm.get('passwordConfirmation').errors?.'mustMatch']"> The password confirmation does not match the entered password</span>