简体   繁体   English

使用 Angular 的密码确认表

[英]Password Confirmation Form Using Angular

I am trying to write a form that involves the logic of confirming the new password value in a confirm password field.我正在尝试编写一个表单,其中涉及在确认密码字段中确认新密码值的逻辑。 I am almost positive it is something to do with how my logic is rendered in the custom validator itself: password.validators.ts.我几乎肯定这与我的逻辑在自定义验证器本身中的呈现方式有关:password.validators.ts。 Without giving the solution up is there something that my logic in the validation function is missing?在不放弃解决方案的情况下,我在验证 function 中的逻辑是否缺失? I have attached my template, customer validator file and component.我附上了我的模板、客户验证器文件和组件。 I would like the confirm password field to throw an error that is stated in my template when my custom validation renders true, this condition would be that the new password field does not match the confirm password field.当我的自定义验证呈现为真时,我希望确认密码字段在我的模板中抛出一个错误,这种情况是新密码字段与确认密码字段不匹配。 When I go to enter values in the field nothing shows up.当我 go 在字段中输入值时,什么都没有显示。

<form [formGroup]="form">
    <div class="form-group">
      <label for="oldPassword">Old Password</label>
      <input 
        formControlName="oldPassword" 
        type="password" 
        class="form-control" 
        id="oldPassword" 
        placeholder="Enter old password">
      <div 
        *ngIf="oldPassword.touched && oldPassword.invalid" 
        class="alert alert-danger"> 
            <div *ngIf="oldPassword.errors.required">Old password is required</div>
            <div *ngIf="oldPassword.errors.cannotContainOldPassword">Old password is not valid</div>
      </div>
    </div>
    <div class="form-group">
      <label for="newPassword">New Password</label>
      <input 
            formControlName="newPassword" 
            type="text" 
            class="form-control" 
            id="newPassword" 
            placeholder="Enter new password">
        <div 
            *ngIf="newPassword.touched && newPassword.invalid" 
            class="alert alert-danger"> 
                <div *ngIf="newPassword.errors.required">New password is required</div>
      </div>
    </div>
    <div class="form-group">
        <label for="confirmPassword">Confirm Password</label>
        <input 
            formControlName="confirmPassword" 
            type="text" 
            class="form-control" 
            id="confirmPassword" 
            placeholder="Confirm new Password">
        <div 
            *ngIf="confirmPassword.touched && confirmPassword.invalid" 
            class="alert alert-danger"> 
                <div *ngIf="confirmPassword.errors.required">Confirm password is required</div>
                <div *ngIf="confirmPassword.errors.confirmNewPassword">Passwords must match</div>
        </div>    
      </div>
    <button type="submit" class="btn btn-primary">Change Password</button>
  </form>
import { AbstractControl, ValidationErrors, ValidatorFn, Validators } from '@angular/forms';

export class PasswordValidators{

    //Make sure old password is correct
    static cannotContainOldPassword(control: AbstractControl) : Promise<ValidationErrors> | null {
        return new Promise((resolve, reject) => {
            setTimeout(()=>{
                if(control.value != "1234"){
                    resolve({cannotContainOldPassword: true});
                }else{
                    resolve(null);
                }
            });
        });
    }

    //Make sure passwords match
    static confirmNewPassword(control: AbstractControl): ValidationErrors | null{
        let newPass = control.get('newPassword');
        let confirmPass = control.get('confirmPassword');
        if(newPass === confirmPass){
            return null;
            //return { confirmNewPassword: true };
        }else{
            return { confirmNewPassword: true };
        }
    }
}
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { PasswordValidators } from './password.validators';

@Component({
  selector: 'password-form-change',
  templateUrl: './password-form-change.component.html',
  styleUrls: ['./password-form-change.component.css']
})
export class PasswordFormChangeComponent {

  form = new FormGroup({
    oldPassword: new FormControl('', Validators.required, PasswordValidators.cannotContainOldPassword),
    newPassword: new FormControl('', Validators.required),
    confirmPassword: new FormControl('', [
      Validators.required, 
      PasswordValidators.confirmNewPassword
    ])
  })

  get oldPassword(){
    return this.form.get('oldPassword');
  }

  get newPassword(){
    return this.form.get('newPassword');
  }

  get confirmPassword(){
    return this.form.get('confirmPassword');
  }
  

}

The problem问题

The problem is that you are applying the validator to the FormControl itself but inside the Validator, you try to access its children (which a Control does not have).问题是您将验证器应用于 FormControl 本身,但在验证器内部,您尝试访问其子级(控件没有)。

form = new FormGroup({
  oldPassword: new FormControl(''),
  newPassword: new FormControl(''),
  // Here you apply the Validator to your control
  confirmPassword: new FormControl('', [PasswordValidators.confirmNewPassword])
})
static confirmNewPassword(control: AbstractControl): ValidationErrors | null{
  // Your control does not have children "newPassword" and "confirmPassword"
  let newPass = control.get('newPassword'); 
  let confirmPass = control.get('confirmPassword');
  if(newPass === confirmPass) { // You are comparing FormControls instead of their values 
    return null;
  } else {
    return { confirmNewPassword: true };
  }
}

The solution解决方案

The simpliest solution would be to move the validator to the form group instead.最简单的解决方案是将验证器移至表单组。 This might also be the preferred solution, since your validator will then be run when either "newPassword" or "confirmPassword" change.这也可能是首选解决方案,因为当“newPassword”或“confirmPassword”更改时,您的验证器将运行。

First, fix your validator to check the values instead of comparing the Controls themselves:首先,修复您的验证器以检查值而不是比较控件本身:

static confirmNewPassword(control: AbstractControl): ValidationErrors | null{
  let newPass = control.get('newPassword').value; // add .value
  let confirmPass = control.get('confirmPassword').value; // add .value
  return newPass === confirmPass ? null : {confirmNewPassword: true };
}

Then apply the validator to the whole form(group):然后将验证器应用于整个表单(组):

form = new FormGroup({
  oldPassword: new FormControl(''),
  newPassword: new FormControl(''),
  // Here you apply the Validator to your control
  confirmPassword: new FormControl('')
}, {validators: PasswordValidators.confirmNewPassword}) // Add the validator to the group instead of your control

Finally, adjust your template to check for the error on the form(group) instead of your control:最后,调整您的模板以检查表单(组)而不是您的控件上的错误:

<div class="form-group">
  <label for="confirmPassword">Confirm Password</label>
  <input 
    formControlName="confirmPassword" 
    type="text" 
    class="form-control" 
    id="confirmPassword" 
    placeholder="Confirm new Password">
  <div 
    *ngIf="confirmPassword.touched && confirmPassword.invalid" 
    class="alert alert-danger"
  > 
    <div *ngIf="confirmPassword.errors?.required">Confirm password is required</div>
    <!--                              ^                    -->
    <!-- Access the errors object by using ?, since errors is null when no error is present -->
    <div *ngIf="form.errors?.confirmNewPassword">Passwords must match</div>
    <!--        ^^^^        -->
    <!-- Check for errors on form here, instead of the control -->
  </div>    
</div>

Here a Stackblitz with a minimal example on this. 这里有一个 Stackblitz ,上面有一个最小的例子。

The issue was in the ngIf directive within my template.问题出在我模板中的 ngIf 指令中。 The problem was that as soon as I typed something into the Confirm Password field, the *ngIf="confirmPassword.touched && confirmPassword.invalid" would render to true hence both the errors under that parent div would go away.问题是,只要我在 Confirm Password 字段中输入内容, *ngIf="confirmPassword.touched && confirmPassword.invalid" 就会呈现为 true,因此该父 div 下的两个错误都会 go 消失。 So the solution was to take insert another div for the password validation underneath.所以解决方案是在下面插入另一个 div 进行密码验证。 The "?"这 ”?” operator must be included or else it will throw "ERROR TypeError: Cannot read property 'confirmNewPassword' of null".必须包含运算符,否则它将抛出“错误类型错误:无法读取属性 'confirmNewPassword' of null”。

<form [formGroup]="form">
    <div class="form-group">
      <label for="oldPassword">Old Password</label>
      <input 
        formControlName="oldPassword" 
        type="password" 
        class="form-control" 
        id="oldPassword" 
        placeholder="Enter old password">
      <div 
        *ngIf="oldPassword.touched && oldPassword.invalid" 
        class="alert alert-danger"> 
            <div *ngIf="oldPassword.errors.required">Old password is required</div>
            <div *ngIf="oldPassword.errors.cannotContainOldPassword">Old password is not valid</div>
      </div>
    </div>
    <div class="form-group">
      <label for="newPassword">New Password</label>
      <input 
            formControlName="newPassword" 
            type="text" 
            class="form-control" 
            id="newPassword" 
            placeholder="Enter new password">
        <div 
            *ngIf="newPassword.touched && newPassword.invalid" 
            class="alert alert-danger"> 
                <div *ngIf="newPassword.errors.required">New password is required</div>
      </div>
    </div>
    <div class="form-group">
        <label for="confirmPassword">Confirm Password</label>
        <input 
            formControlName="confirmPassword" 
            type="text" 
            class="form-control" 
            id="confirmPassword" 
            placeholder="Confirm new Password">
        <div 
            *ngIf="confirmPassword.touched && confirmPassword.invalid" 
            class="alert alert-danger"> 
                <div *ngIf="confirmPassword.errors.required">Confirm password is required</div>
        </div> 
        <div 
          *ngIf="confirmPassword.valid && form.invalid && form.errors?.confirmNewPassword" 
          class="alert alert-danger">
          Passwords should match
        </div>   
      </div>
    <button type="submit" class="btn btn-primary">Change Password</button>
  </form>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM