Angular 2 匹配表单中的密码

Angular 2 Match password in a form

我知道其他时候也有人以类似的形式问过这个问题,但我的情况有点不同;让我解释一下:

我有一个重设密码表单,有 3 个字段(旧密码、新密码、确认密码)。当然,我需要检查提交的密码是否等于提交的确认密码,我想在单击提交之前执行此操作。我定义的形式如下(在component.ts中)

this.form = fb.group({
  // define your control in you form
  oldpassword: ['', Validators.required],
  password: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(10)]],
  confirmPassword: ['', [Validators.required, Validators.minLength(4), Validators.maxLength(10)]]
}, {
  validator: PasswordValidation.MatchPassword // your validation method
});

export class PasswordValidation {

static MatchPassword(AC: AbstractControl) {
    const password = AC.get('password').value; // to get value in input tag
    const confirmPassword = AC.get('confirmPassword').value; // to get value in input tag
    if (password !== confirmPassword) {
      AC.get('confirmPassword').setErrors({MatchPassword: true})
    } else {
        return null
    }
}
}  

这是问题所在,如果我在编译 "new password" 之前更改 "confirm password field",则表格无效。换句话说,如果我尊重字段的垂直顺序,一切都可以,但如果我按不同的顺序编译字段,那么表单仍然无效。

这里是 html 代码:(如您所见,它有点令人困惑,因为我有其他 UX 约束 ehich 对应于用户可能的交互)

<form [formGroup]="form" novalidate (ngSubmit)="modal.open()">
        <div class="form-group">
          <label for="oldpassword">Inserisci vecchia password</label>
          <input type="password" id="oldpassword" class="form-control" formControlName="oldpassword">
          <div
            *ngIf="form.controls['oldpassword'].hasError('required') && form.controls['oldpassword'].touched"
            class="alert alert-danger">
            Campo obbligatorio
          </div>
        </div>
        <div class="form-group">
          <label for="password">Inserisci nuova password</label>
          <input type="password" id="password" class="form-control" formControlName="password">
          <div *ngIf="form.controls['password'].hasError('required') && form.controls['password'].touched"
               class="alert alert-danger">
            Campo obbligatorio
          </div>
          <div *ngIf="form.controls['password'].hasError('minlength') && form.controls['password'].touched"
               class="alert alert-danger">
            Lunghezza minima: 4 caratteri.
          </div>
        </div>
        <div class="form-group">
          <label for="confirmPassword">Ripeti nuova password</label>
          <input type="password" class="form-control" id="confirmPassword" formControlName="confirmPassword">
          <div class="alert alert-danger"
               *ngIf="form.errors?.MatchPassword || (form.controls['confirmPassword'].hasError('required') && form.controls['confirmPassword'].touched)">
            Le password non corrispondono
          </div>
        </div>
        <div *ngIf="!this.state.controlloIn; else elseBlock">
          <button type="submit" class="btn btn-primary btn-update" [disabled]="!form.valid || this.controlloInvia">
            Invia Richiesta
          </button>
        </div>
        <ng-template #elseBlock>
          <button type="submit" class="btn btn-primary btn-update" [disabled]="true">
            Invia Richiesta
          </button>
        </ng-template>
      </form>

我不是 angular 专家,所以如果您能给我建议其他最佳实践,我将非常高兴。感谢大家

this.profileForm = this.formBuilder.group({
  password: [this.profile.password, [
    Validators.required,
    Validators.minLength(4)]
  ],
  passwordCheck: [this.profile.password, [
    Validators.required,
    Validators.minLength(4)
  ]],
  oldPassword: [this.profile.oldPassword, [
    Validators.required]],
}, { validator: matchingPasswordsValidator('password', 'passwordCheck') });

这是我用于更改密码的表格。 它使用一个单独的验证器,该验证器不验证它验证整个表单的字段。

export function matchingPasswordsValidator(passwordKey: string, confirmPasswordKey: string) {
  return (group: FormGroup): { [key: string]: any } => {
    let password = group.controls[passwordKey];
    let confirmPassword = group.controls[confirmPasswordKey];

    if (password.value !== confirmPassword.value) {
      return {
        mismatchedPasswords: true
      };
    }
  }
}

@Directive({
  selector: '[appMatchingPasswordsValidator]',
  providers: [{
    provide: NG_VALIDATORS, useExisting: MatchingPasswordsValidatorDirective, multi: true
  }]
})
export class MatchingPasswordsValidatorDirective {

  constructor() { }

  validate(c: AbstractControl) {
    matchingPasswordsValidator("test", "test");
  }
}

那么这就是用来匹配密码的指令。或您在表格中提供的任何 2 个键。

您正在直接在确认字段中设置错误。如果您不再触摸该字段,则会在其上设置错误并且永远不会被删除。 Angular 运行 验证器仅针对已编辑的字段,因为您可以合理地认为如果某个字段被标记为错误且未被编辑,它仍处于错误状态。

我建议您将此错误直接放在 FormGroup 上:

static MatchPassword(AC: AbstractControl) {
    const password = AC.get('password').value; // to get value in input tag
    const confirmPassword = AC.get('confirmPassword').value; // to get value in input tag
    if (password !== confirmPassword) {
      return {MatchPassword: true};
    } else {
        return null
    }
}
<div class="alert alert-danger"
               *ngIf="form.errors?.MatchPassword || (form.controls['confirmPassword'].hasError('required') && form.controls['confirmPassword'].touched)">
            Le password non corrispondono
          </div>

我刚刚 运行 解决了这个问题并找到了不同的修复方法。当密码匹配时,我在返回 null 之前调用 AbstractFormControl 的 updateValueAndValidity 函数(onlySelf 为真,emitEvent 为假)。这使我能够对密码和确认密码输入进行验证。我可以在密码前输入确认密码,验证状态正常显示。

static MatchPassword(AC: AbstractControl) {
  const password = AC.get('password').value; 
  const confirmPassword = AC.get('confirmPassword').value; 
  if (password !== confirmPassword) {
    AC.get('confirmPassword').setErrors({MatchPassword: true})
  } else {
    AC.get('confirmPassword').updateValueAndValidity(
             {onlySelf: true, emitEvent: false}
          );
    return null;
  }
}

我知道这是对您问题的迟到回答,但我想展示一种方法。 您可以通过在 ngModel.

上调用 .value 来比较输入值

您可以在下面的代码块中看到它是如何工作的

 <div *ngIf="newPassword.dirty || newPassword.touched">
    <div class="alert alert-danger" *ngIf="newPassword.value.match(passwordCurrent.value)">
        Current password and New Password can't match.
    </div>
</div>

长版代码

    <div class="form-group">
        <div class="input-group input-group-alternative">
            <div class="input-group-prepend">
                                                <span class="input-group-text"><i
                                                        class="fa fa-unlock-alt"></i></span>
            </div>
            <input required minlength="6" [(ngModel)]="passwordOneIn"
                   #newPassword="ngModel" name="newPassword" class="form-control"
                   placeholder="New Password" type="password">
        </div>
    </div>

    <!--#####check if the password and current password match########-->
    <div *ngIf="newPassword.dirty || newPassword.touched">
        <div class="alert alert-danger" *ngIf="newPassword.value.match(passwordCurrent.value)">
            Current password and New Password can't match.
        </div>
    </div>

    <div *ngIf="newPassword.invalid && (newPassword.dirty || newPassword.touched)"
         class="alert alert-danger">
        <div *ngIf="newPassword.errors.required">
            password is required.
        </div>
    </div>

    <div class="form-group">
        <div class="input-group input-group-alternative">
            <div class="input-group-prepend">
                <span class="input-group-text"><i class="fa fa-unlock-alt"></i></span>
            </div>
            <input required minlength="6" [(ngModel)]="passwordTwoIn"
                   #retypedPassword="ngModel" name="retypedPassword"
                   class="form-control" placeholder="Retype Password" type="password">
        </div>
    </div>


    <div *ngIf="retypedPassword.invalid && (retypedPassword.dirty || retypedPassword.touched)"
         class="alert alert-danger">
        <div *ngIf="retypedPassword.errors.required">
            password is required.
        </div>
    </div>

    <!--##### check if the new password and retyped password match ########-->
    <div *ngIf="retypedPassword.dirty || retypedPassword.touched">
        <div class="alert alert-danger" *ngIf="!newPassword.value.match(retypedPassword.value)">
            New password and Retyped Password don't match.
        </div>
    </div>

    <button [disabled]="changePasswordFrom.form.invalid || newPassword.value.match(passwordCurrent.value) || !newPassword.value.match(retypedPassword.value)"
            type="submit" class="btn btn-primary mt-4">Change Password</button>
</div>