Skip to content

Instantly share code, notes, and snippets.

@slavafomin
Last active March 15, 2023 13:35
Show Gist options
  • Save slavafomin/17ded0e723a7d3216fb3d8bf845c2f30 to your computer and use it in GitHub Desktop.
Save slavafomin/17ded0e723a7d3216fb3d8bf845c2f30 to your computer and use it in GitHub Desktop.
Angular 2 match other field validator / Password match validator

Angular 2 match other field validator

This custom validator for Angular 4 allows you to have fields that must be equal to some other fields. Such validator is very useful for password confirmation validation, for example.

Besides checking if two values are matching, it also subscribes to changes from other control and re-validates when either of two controls is updated.

Usage

private constructForm () {
  this.form = this.formBuilder.group({
    email: ['', [
      Validators.required,
      Validators.email
    ]],
    password: ['', Validators.required],
    repeatPassword: ['', [
      Validators.required,
      matchOtherValidator('password')
    ]]
  });
}

More up-to-date validators could be found here: moebius-mlm/ng-validators.

import {FormControl} from '@angular/forms';
export function matchOtherValidator (otherControlName: string) {
let thisControl: FormControl;
let otherControl: FormControl;
return function matchOtherValidate (control: FormControl) {
if (!control.parent) {
return null;
}
// Initializing the validator.
if (!thisControl) {
thisControl = control;
otherControl = control.parent.get(otherControlName) as FormControl;
if (!otherControl) {
throw new Error('matchOtherValidator(): other control is not found in parent group');
}
otherControl.valueChanges.subscribe(() => {
thisControl.updateValueAndValidity();
});
}
if (!otherControl) {
return null;
}
if (otherControl.value !== thisControl.value) {
return {
matchOther: true
};
}
return null;
}
}
@009topersky
Copy link

@ErvinLlojku Thumbs Up! Saves my day!

@MuizMahdi
Copy link

Thank you, sir.

For those who didn't get how it works on the view:
*ngIf="formGroup.controls['formControl'].errors?.matchOther"

matchOther: true, if they don't match.

@diosney
Copy link

diosney commented May 16, 2018

I like it since it performs the validation on the control itself, and not on the FormGroup, which helps a lot to style the fields and to localize quickly the errors.

Thanks.

@alex-steinberg
Copy link

You...are...such...a...legend

Copy link

ghost commented Jul 27, 2018

@ErvinLlojku, there's a small problem with your implementation.
If you fill the secondControl value before the firstControl and they happen to match, the validator will state that the form is invalid (and they are not). The other way around it works fine.

@nachovaona
Copy link

otherControl.valueChanges.subscribe(() => {
    thisControl.updateValueAndValidity();
});

Should this not be unsubscribed? It will keep on existing throughout the project even after the form has been destroyed?

You are right. I solved it by adding a mark on the control to subscribe just once:
if (!thisControl['subscribed']) {
thisControl['subscribed'] = true;
otherControl.valueChanges.subscribe(() => {
thisControl.updateValueAndValidity();
});
}

@anandundavia
Copy link

Hi,

I reduced the snippet to this:

  matchOtherValidator(otherControlName: string) {
    return function matchOtherValidate(control: FormControl) {
      if (!control.parent) {
        return null;
      }
      const otherControl = control.parent.get(otherControlName) as FormControl;
      if (!otherControl) {
        throw new Error('matchOtherValidator(): other control is not found in parent group');
      }
      otherControl.valueChanges.subscribe(() => {
        control.updateValueAndValidity();
      });
      if (otherControl.value !== control.value) {
        return { matchOther: true };
      }
      return null;
    };
  }

Is there a difference between this snippet and the one which you provided?

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment