密码和确认密码字段验证 angular2 反应形式

Posted

技术标签:

【中文标题】密码和确认密码字段验证 angular2 反应形式【英文标题】:password and confirm password field validation angular2 reactive forms 【发布时间】:2017-09-15 04:36:54 【问题描述】:

我需要使用响应式 angular2 检查密码和确认密码字段是否具有相同的值。我确实在这里看到了很多相同的答案,Angular 2 form validating for repeat password,Comparing fields in validator with angular2,但似乎没有一个对我有用。有人可以帮忙。“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;
    

【问题讨论】:

FormGroup 的 Angular 文档现在有 an example 这个确切的用例。 这是另一个version 【参考方案1】:

这最终对我有用 -

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.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'),validator: this.checkIfMatchingEmail('email', 'email1')]); 我们如何在html表单中使用这个 @SharanAinapurapu 你有什么解决办法吗? 此方法将绕过所需的验证器,因为您正在覆盖错误。【参考方案2】:

最好是在表单组内有一个嵌套组,我们有一个自定义验证器使用passwordconfirmPass 检查表单组,因此当任何一个字段发生更改时,验证器都会被触发,因为之前它只在 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')"

当然,您不需要嵌套组,但最好不要在每次表单发生任何更改时都触发自定义验证器。这样,只有在这个内部表单组发生更改时才会触发它。

【讨论】:

还有一个边缘情况需要覆盖。如果您正确输入了两个密码,然后假设您想再次更改原始密码字段的值,则不会显示错误,并且 confirm_password 字段仍然保持有效,直到再次触摸它。【参考方案3】:

对于那些想要添加自定义验证器而不被强制通过表单组验证的人,可以在定义表单后添加验证器。

这种方法的一个优点是将错误添加到表单控件而不是表单组。这样更容易显示与字段相关的错误,因为我们可以直接在字段/表单控件本身上检查错误。

我是这样实现的:

自定义验证器

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"]
    );
  

验证器在定义表单后设置,以便能够访问密码控件并将其作为参数传递给自定义验证器。

【讨论】:

但是如果你更新“密码”(填写正确的值),“密码确认”输入将不会正确更新。【参考方案4】:

我在实现这个时遇到了一些问题,当我使用自定义验证器和 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>

这将创建一个包含两个需要匹配的输入字段的表单。

【讨论】:

【参考方案5】:

使用响应式表单 - 我认为这是最简单的方法

更改密码.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;
      ,
    
  );

更改密码.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>

【讨论】:

【参考方案6】:

这是我使用的匹配验证器:

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

【讨论】:

【参考方案7】:

如果你想这样做,你需要将函数绑定到当前的“this”上下文。 传递this.validatePasswordConfirmation.bind(this) 但请注意,此函数将传递给 FormControl 以进行确认,而不是像您在函数签名中所述的 FormGroup 。

【讨论】:

谢谢,我能得到这个,但表单在“this”中仍未定义。你能告诉我如何获取用户输入的密码值吗?this.addEditUserForm 是未定义的。 我可以让它工作***.com/questions/31788681/…。感谢您的帮助。【参考方案8】:

我采用了一种适用于任何控件的不同方法。首先我定义了表单的基本控件:

    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;

    ;

【讨论】:

【参考方案9】:

您的答案应该可以正常工作。您只需添加.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;
    

【讨论】:

【参考方案10】:

如果您不想通过自定义验证器,您可以创建一个独立的输入字段,因此不会在您的 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;
  

【讨论】:

【参考方案11】:

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 反应形式的主要内容,如果未能解决你的问题,请参考以下文章

反应采取错误验证的多步骤形式

使用引导验证器验证密码并确认密码字段

我有一个密码和一个确认密码字段,我已经使用 laravel 对其进行了验证,但即使两个字段的密码相同,它也显示不匹配?

反应密码验证 onChange

Spring Security Core 和用于确认密码字段的自定义验证器是不是可行?

django登录注册验证之密码包含特殊字符,确认密码一致实现