Pankaj
Pankaj

Reputation: 10095

Compare two controls value validation

About

I am trying to compare the value of password and confirm password and if found mismatch then message to be shown.

Due to some reasons it shows nothing. Am I missing anything in below code?

Form Group Validation work

    this.resetPasswordForm = new FormGroup({
        password: new FormControl("", [
            Validators.required,
            Validators.minLength(8), 
            Validators.maxLength(40)
        ]),
        password_confirmation: new FormControl("", [
            Validators.required
        ]),
    });

Html

    <input type="password" formControlName="password_confirmation" />
            
    <span *ngIf="resetPasswordForm.controls.password_confirmation.errors
        && resetPasswordForm.controls.password_confirmation.dirty 
        && resetPasswordForm.controls.password_confirmation.touched">
        
        <ng-container *ngIf="resetPasswordForm.controls.password_confirmation.errors.required;else second">
            Confirm password is required
        </ng-container>
        <ng-template #second>
            <ng-container *ngIf="resetPasswordForm.controls.password_confirmation.value 
                == resetPasswordForm.controls.password.value">
                Password and confirm password mismatch
            </ng-container>
        </ng-template>
    </span>

Upvotes: 3

Views: 6019

Answers (3)

N.F.
N.F.

Reputation: 4184

Your password_confirmation validation only has Validation.required. So when this field has any value, resetPasswordForm.controls.password_confirmation.errors will be false and any error message will not be shown.

You have to create a validation function that checks the password and password_confirmation values are identical. This will resetPasswordForm.controls.password_confirmation.errors makes true when two fields have different values.


const validatePasswordMatch = (control: AbstractControl): {[key: string]: any} | null => {
  const password = this.resetPasswordForm?.get('password')?.value as string;
  const passwordConfirm = control.value as string;

  if (password !== passwordConfirm) {
    return {passwordMatch: true};
  }

  return null;
};


this.resetPasswordForm = new FormGroup({
    password: new FormControl("", [
        Validators.required,
        Validators.minLength(8), 
        Validators.maxLength(40)
    ]),
    password_confirmation: new FormControl("", [
        Validators.required,
        validatePasswordMatch
    ]),
});

Then you can show password confirmation error like this.

    <ng-template #second>
        <ng-container *ngIf="resetPasswordForm.controls.password_confirmation.errors.passwordMatch">
            Password and confirm password mismatch
        </ng-container>
    </ng-template>

Upvotes: 6

Wazed rifat
Wazed rifat

Reputation: 11

you will have to add validation function to formGroup which will match values of password & password_confirmation. I have also handled error using a variable so that I can bring error handler to ts file from HTML file. Your Html can look like below :

<form [formGroup]="resetPasswordForm" class="d-flex flex-column">
    <input type="password" formControlName="password" />
    <input type="password" formControlName="password_confirmation" />

    <span *ngIf="errorMessage">{{ errorMessage }}</span>
</form>

Your ts can look like below :

export class AppComponent implements OnInit    {
    resetPasswordForm: FormGroup;
    errorMessage: string = null;
    
    ngOnInit(): void {
        this.resetPasswordForm = new FormGroup({
            password: new FormControl("", [
                    Validators.required,
                    Validators.minLength(8), 
                    Validators.maxLength(40)
            ]),
            password_confirmation: new FormControl("", [
                    Validators.required
            ]),
        }, 
        {
            validators: this.customValidatorFN
        });

        this.resetPasswordForm.valueChanges.subscribe(newValue => {
            this.showErrors();
        });
    }

    showErrors() {
        const confirmPassError = this.resetPasswordForm.get('password_confirmation').errors;
        const misMatchError = this.resetPasswordForm.errors;

        if (confirmPassError && 'required' in confirmPassError) {
            this.errorMessage = 'Confirm password is required';
        }
        else if (misMatchError) {
            this.errorMessage = Object.keys(misMatchError)[0];
        }
        else {
            this.errorMessage = null;
        }
    }

    customValidatorFN(control: AbstractControl): ValidationErrors | null {
        const pass = control.get('password');
        const confirmPass = control.get('password_confirmation');
        if (pass.value !== confirmPass.value) {
            return {'Password and confirm password mismatch': true};
        }
        return null;
    }
}   

Upvotes: 0

ianpea
ianpea

Reputation: 99

Have you created a validator function to the FormGroup obj in your component.ts file?

Basically you take in the FormControl values from the FormGroup object you defined and created IN the html template TO the validator function, and within that validator function, you retrieve your form control values, check it, update it, patch the value, whatever, and then throw the error out in any form you like.

Then in your html template, retrieve that error from the FormGroup you created, and you can show your error accordingly.

In this case I throw the error as null if there's no error, or an object with the error message if there is an error. Like this:

import { ValidatorFn, AbstractControl, ValidationErrors } from '@angular/forms';
    
export const exceptionValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
    const justification = control.get('justification')?.value ?? '';
    var errors: any = {justficiationErr: ''};

    if(justification === '' || justification === 'test'){
        justficiationErr = "Invalid field.";
    }

    return errors.justifiactionErr ? errors.justificationErr : null;
};    

And use it in your component.ts file:

mainForm:FormGroup;
    
constructor(
  private fb: FormBuilder,
) 

ngOnInit():void{
    initializeForm();
}

initializeForm():void{
    this.mainForm = this.fb.group(
      {
        justification: ['', Validators.required] <-- this has to be your `formControlName` property
      },
      { validators: exceptionValidator } <-- validator func
    );
}       

And the html template, you retrieve your errors like this, notice the [formGroup] is bound to a variable craeted in the component.ts file:

<div class="col-12" [formGroup]="mainForm">
  <textarea formControlName="justification" class="field"
      maxlength="100" pInputTextarea style="width: 100%" autofocus 
      placeholder="Enter Justification"></textarea>
  <div *ngIf="mainForm.errors != null">{{mainForm.errors.justificationErr}}</div> <-- important
</div>

Let me know if this helps. Or you can visit this link https://angular.io/guide/form-validation, as Angular explains it best, if you haven't already, take the time to understand what they are saying, it will really help when you look thru documentations next time.

Upvotes: 2

Related Questions