Search code examples
angularangular2-forms

Angular 2 Match password in a form


I know this question has been asked other times, in similar forms, but I have a little different situation; let me explain:

I have a reset password form, with 3 fields (old password, new password, confirm password). Of course I need to check if the submitted passowrd is equal the submittedw confirmpassword and I want to do it before clicking submit. I defined the form as follows (in the 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
    }
}
}  

Here is the problem, the form is not valid if I change the "confirm password field" before compiling the "new password" one. In other words, if I respect vertical o9rder of the fields, all is OK, but if I compile the fields in different order, then the form is still invalid.

here is the html code : (as you can see, it is a bit confusing because I have other UX constraint ehich corresponds to user possible interactions)

<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>

I'm not an angular expert, so if you please could suggest me other best practice I'll be really happy. thanks to all


Solution

  • You are setting your errors directly on the confirmation field. If you don't touch that field anymore, errors are set upon it and will never get removed. Angular run validators against a field only if it has been edited because you can legitimately think that if a field is marked as error and hasn't been edited, it is still in error state.

    I would recommend you to put this error directly upon the FormGroup instead :

    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>