1

This code in my form-validators.ts:

console.log('password:', password?.value); console.log('confirmPwd:', confirmPwd?.value); 

always fetched me undefined, causing the custom validation (matchPwdValidator()) to constantly return false. If I fetched confirmPwd in the switch, it will print out the correct details. Below is a summarized version of my codes.

form-validators.ts

import { AbstractControl, ValidatorFn, Validators } from "@angular/forms"; export class FormValidators { ... static matchPwdValidator(): ValidatorFn { return (control: AbstractControl): { [key: string]: any } | null => { const password = control.get("password"); const confirmPwd = control.get("confirmPwd"); console.log('password:', password?.value); console.log('confirmPwd:', confirmPwd?.value); if (!password || !confirmPwd || password.value !== confirmPwd.value) { return { PwdNotMatched: true }; } return null; }; } } 

form.component.ts

import { Component } from "@angular/core"; import { FormBuilder, FormGroup } from "@angular/forms"; import { FormValidators } from "../utilities/form-validators"; @Component({ selector: "app-form", templateUrl: "./form.component.html", styleUrls: ["./form.component.scss"], }) export class FormComponent { cpwdError: boolean = false; sampleForm: FormGroup; constructor( private formBuilder: FormBuilder, ) { this.sampleForm= this.formBuilder.group( { ... password: ["", FormValidators.passwordValidator()], confirmPwd: ["", FormValidators.matchPwdValidator()], }, ); ... this.sampleForm.get('confirmPwd')?.statusChanges .subscribe(() => { this.updateErrorFlags('confirmPwd'); }); } private updateErrorFlags(controlName: string): void { const control = this.sampleForm.get(controlName); if (control) { switch (controlName) { ... case 'confirmPwd': this.cpwdError = control.hasError('PwdNotMatched') && control.dirty; break; } } } } 
3
  • 1
    try control.parent?.get() inplace of control.get(""); Commented Jan 8, 2024 at 13:16
  • Thank you, changing to control.parent?.get() fixed the problem. May I know why control.get("") doesn't work? Commented Jan 8, 2024 at 14:49
  • A Validator can be "attached" to a FormControl or to a FormGroup (or to a FormArray). In your case, your validator is "attached" to a control (the formControl "confirmPwd"). control.parent is the formGroup "sampleForm". Commented Jan 8, 2024 at 15:05

2 Answers 2

2

You are set the matchPwdValidator validation to the "confirmPwd" FormControl. It can't find any control with name: "password" and "confirmPwd". You should get both controls from the root form group of the current form control.

const password = control.parent?.get('password'); const confirmPwd = control.parent?.get('confirmPwd'); 

Demo @ StackBlitz

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, changing to your given answer works like a charm. However I still don't understand why it doesn't work with control.get(""). Is it because my matchPwdValidator() is not in form.component.ts where I declare my FormGroup? Sorry if I am slow.
See that Angular not "validate automatically" an input if you don't use setValue or change the input. (So if you change the password after the repeatpassword can be equals but you see the error). For me the more transparent solution is force the validation like this SO
0

I think you are doing password-matching validation all code here It's proper working and you change as per you need

html file

<div class="col-4"> <form [formGroup]="registerForm" #form="ngForm"> <div class="col-md-12"> <div class="form-group required"> <div class="services-form"> <input maxlength="50" formControlName="Password" maxlength="50" placeholder="Password" /> <label>Password</label> </div> </div> </div> <!-- Confirm password --> <div class="col-sm-6"> <div class="form-group required"> <div class="services-form"> <input type="password" formControlName="ConfirmPassword" autocomplete="off" placeholder="Confirm password" /> <label>Confirm password</label> <div *ngIf=" registerForm.get('ConfirmPassword')?.touched && registerForm.get('ConfirmPassword')?.invalid " class="input-error" > {{ !registerForm.get('ConfirmPassword')?.value ? 'The confirm password field is required.' : 'The password and confirm password fields do not match' }} </div> </div> </div> </div> </form> </div> 

ts file :

registerForm!: FormGroup; constructor(private formBuilder: FormBuilder) {} ngOnInit() { this.registerForm = this.formBuilder.group( { Password: ['', [Validators.required]], ConfirmPassword: ['', Validators.required], }, { validator: MustMatch('Password', 'ConfirmPassword'), } ); } 

must-match.validator.ts

import { FormGroup } from '@angular/forms'; // custom validator to check that two fields match export function MustMatch(controlName: string, matchingControlName: string) { return (formGroup: FormGroup) => { const control = formGroup.controls[controlName]; const matchingControl = formGroup.controls[matchingControlName]; if (matchingControl.errors && !matchingControl.errors?.['mustMatch']) { // return if another validator has already found an error on the matchingControl return; } // set error on matchingControl if validation fails if (control.value !== matchingControl.value) { matchingControl.setErrors({ mustMatch: true }); } else { matchingControl.setErrors(null); } }; } 

please check in stackBlitz

https://stackblitz.com/edit/angular13-reactive-form-validation-jqtqvw?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2Fapp.component.html,src%2Fapp%2Fmust-match.validator.ts,src%2Fapp%2Fapp.module.ts

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.