Angular Validation Custom Control does not retrieve form values

In my form-validators.ts file, I encountered an issue where the code snippet below always returned undefined, causing the custom validation function matchPwdValidator() to consistently return false. By moving the logic to fetch confirmPwd inside the switch statement, I was able to retrieve the correct values. A condensed version of my code is provided below.

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

Answer №1

You have assigned the validation matchPwdValidator to the "confirmPwd" FormControl, but it is unable to locate any controls named "password" and "confirmPwd". To resolve this issue, you need to retrieve both controls from the root form group of the current form control.

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

Check out the demo on StackBlitz

Answer №2

It appears that the password-matching validation code implemented here is functioning correctly. Feel free to modify it according to your requirements.

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

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the reason behind continuously receiving the error message stating "Not all code paths return a value here"?

Can someone help me understand why I am consistently encountering this error message from typescript? PS. I am aware that in this scenario I could simply use a boolean and not create a function, but my focus here is on typescript. I keep receiving the er ...

Why does typescript need a Node.js module?

I have come across many questions similar to this one. This is the workaround I am currently experimenting with, specifically related to the MySQL module in Node.js. 1. Enter the following commands: npm install typescript npm install mysql To use TypeS ...

What could be causing the validator to display an error for the same field when in edit mode within an angular reactive form

I need a unique name field in my form, which is used for both user registration and edit mode. My validation process involves sending a request to the backend to retrieve all existing usernames and then storing them in an array list. When a user enters a ...

"Zone has been successfully loaded" - incorporating angular universal ssr

I am currently working on an Angular project and I am looking to implement server-side rendering. To achieve this, I decided to use Angular Universal. The browser module of my project was successfully built, but I encountered the following issue during the ...

The custom classes do not work with the ngx-bootstrap modal feature

I'm in the process of setting a new width for a modal that has been created using BsModalService. I have found that I can't change it by assigning a custom class, but only by utilizing the given classes like 'modal-xl'. Can you explain ...

Utilizing event listeners with image elements in React for interactive typing experience

When I attempt to type the event as React.ChangeEvent<HTMLImageElement> in order to make the e.target.src work, I encounter the following error messages in the imageFound and ImageNotFound functions: Type '(evt: React.ChangeEvent) => void&a ...

Can you explain the concept of a "subpath pattern" in NodeJS?

As I was browsing through a blog post discussing the latest features of Angular 13, one particular point caught my attention: The statement that Node.js versions older than v12.20 are no longer supported by Angular packages because they utilize the Node. ...

Ways to verify the existence of components in a viewContainerRef in Angular

When dynamically adding components, I follow this approach: export class CustomersOverviewComponent implements OnInit, OnDestroy { @ViewChild(PanelDirective) customerHost: PanelDirective; constructor(private componentFactoryResolver: ComponentFactor ...

Typescript provides the flexibility to construct incomplete or partially valid objects

My attempt to create a partial helper function in Typescript led me to an incorrect version that went unnoticed by Typescript: Typescript version: 5.2.2 type A = { a: number; b: string }; // incorrect const buildPartialBad = (key: keyof A, val: A[keyof A ...

What is the best way to confirm the return type of a React.Component instance?

When working with TypeScript, there is a React Component called Cell: class Cell extends Component<void, void> { ... } Using it like this: <Cell /> The return type being received is JSX.Element. However, I want to make sure that the return ...

What are some recommended strategies for incorporating nested routes with separate pages in a React application?

In my React (TypeScript) project, I have a basic routing setup. There's a constant display of a Header and a Footer, a home component for the frontpage, and a Projects section for showcasing past projects worked on. However, I'm facing an issue w ...

Changing a field in a Firestore document to a boolean results in the type being converted to a

I manually created this Firestore document using the console, setting enabled as a boolean type. Now, I am expanding on the functionality to update it in Angular with the following code snippet. activateMenuItem(venueId: string, menuId: string, menuItem ...

Having issues with Angular 2 CLI commands not functioning properly

My system is equipped with all the necessary packages to execute the following command: ng generate component navigation However, every time I run this command, it triggers a "New file" operation in an unfamiliar text editing program. The interface of th ...

Generate several invoices with just a single click using TypeScript

I'm interested in efficiently printing multiple custom HTML invoices with just one click, similar to this example: https://i.sstatic.net/hAQgv.png Although I attempted to achieve this functionality using the following method, it appears to be incorr ...

Tips for utilizing a particular field in a JSON object as the data origin while employing ng2-completer

As a newcomer to Angular and ng2 completer, I am working with an array of objects structured like this: var concepts = [ { id:, code:, concept:, display: } ............ ] The goal is to have the data source for auto suggest feature as the di ...

Creating migrations in TypeORM without the need for a specific ormconfig file

When it comes to connecting to a database with TypeORM, I have opted to set my Connection Options programmatically within my project's code using a regular TypeScript file. Here is an example of how I do this: // src/database/createConnection.ts impo ...

Extracting data from a JSON object using Angular 2

I need advice on the most efficient way to handle JSON within my angular2 application. The JSON data I am working with includes: { "rightUpperLogoId": { "id": 100000, "value": "" }, "navbarBackgroundColorIdCss": { "id" ...

Create a d.ts file in JavaScript that includes a default function and a named export

While working on writing a d.ts file for worker-farm (https://github.com/rvagg/node-worker-farm), I encountered an issue. The way worker-farm handles module.exports is as follows: module.exports = farm module.exports.end = end When trying to replica ...

Issues are arising with Angular Form where the FormControl is not being properly set up for the first field in my form

After grappling with this issue for several weeks, I am still unable to pinpoint the cause. (Angular version: 16.1.4) The form component is populated using a BehaviorSubject, and although the console prints out the correct values for both the form and dat ...

The expect.objectContaining() function in Jest does not work properly when used in expect.toHaveBeenCalled()

Currently, I am working on writing a test to validate code that interacts with AWS DynamoDB using aws-sdk. Despite following a similar scenario outlined in the official documentation (https://jestjs.io/docs/en/expect#expectobjectcontainingobject), my asser ...