Is there a way to initiate validations for inputs within ReactiveForms?

After creating a form using Reactive Forms, I have implemented functionality for users to set a new password. The process involves entering both the old and new passwords, as well as confirming the new password. Throughout development, I considered the following scenarios:

  • The new password cannot be the same as the old password
  • The new password and confirmation password must match

While the development is functional, there is one aspect that could be improved. Currently, validation only occurs when something in an input field is changed. However, I would like the validation to occur when changing the new password to confirm it instantaneously for any errors. I've come across the updateValueAndValidity function that can potentially help with this. Can anyone provide guidance on how to implement this?

Here's a snippet of my code:

// TS
changePasswordForm: FormGroup;
submitted = false;

ngOnInit() {
    // Initialize forms
    this.initChangePasswordForm();
  }

private initChangePasswordForm() {
    // Form initialization
    this.changePasswordForm = this.formBuilder.group({
      old_password: [null, Validators.pattern('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\\w\\s]).{8,}$')],
      new_password: [null, this.customComparePasswordValidator],
      confirm_password: [null, Validators.required]
    });
}

customComparePasswordValidator(control: FormControl) {
    const newPassword = control.value;
    if (newPassword && newPassword.length) {
      const oldPassword = control.parent.value.old_password;
      if (oldPassword && oldPassword.length && newPassword.toLowerCase().includes(oldPassword.toLowerCase())) {
        return { newPasswordIncludesOldPassword: true };
      }
      const pattern = new RegExp('^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\\w\\s]).{8,}$');
      if (!pattern.test(newPassword)) {
        return { newPasswordInvalid: true };
      }
    } else {
      return { required: true };
    }
}
// HTML
<input matInput type="password" placeholder="Current Password" formControlName="old_password" required>
<p *ngIf="changePasswordForm.get('old_password').invalid && (changePasswordForm.get('old_password').dirty || changePasswordForm.get('old_password').touched)">
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('old_password').hasError('required')">Please enter current password</mat-error>
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('old_password').hasError('pattern')">Use 8 or more characters with a mix of uppercase and lowercase letters, numbers, and symbols</mat-error>
          </p>

<input matInput type="password" placeholder="New Password" formControlName="new_password" required>
<p *ngIf="changePasswordForm.get('new_password').invalid && (changePasswordForm.get('new_password').dirty || changePasswordForm.get('new_password').touched)">
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('required')">Please enter new password</mat-error>
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('newPasswordInvalid')">Use 8 or more characters with a mix of uppercase and lowercase letters, numbers, and symbols</mat-error>
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('new_password').hasError('newPasswordIncludesOldPassword')">New password should not include old password</mat-error>
          </p>

<input matInput type="password" placeholder="Confirm Password" formControlName="confirm_password" appConfirmEqualValidator="new_password" required>
<p *ngIf="changePasswordForm.get('confirm_password').invalid && (changePasswordForm.get('confirm_password').dirty || changePasswordForm.get('confirm_password').touched)">
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('confirm_password').hasError('required')">Please confirm the password</mat-error>
            <mat-error class="custom-validation-error" *ngIf="changePasswordForm.get('confirm_password').hasError('notEqual') && !changePasswordForm.get('confirm_password').hasError('required')">Passwords do not match</mat-error>
          </p>

You can access my StackBlitz project at: https://stackblitz.com/edit/example-angular-material-reactive-form-sr1keu?file=app%2Fapp.component.html

Answer №1

When you modify the FormControl, the validator only "checks". This means that you can ensure the validity of one control when another is changed. For example, in the FormControl "new_password", you can simply do the following:

<input matInput ... formControlName="new_password"
     (input)="changePasswordForm.get('confirm_password').updateValueAndValidity()"  />

(Similarly with the other FormControl)

After creating the form, you can also subscribe to valueChanges - just remember to unsubscribe later:

private initChangePasswordForm() {
    // After creating the formGroup
    this.changePasswordForm = this.formBuilder.group({...}

    // Subscribe to changes in "new_password"
    this.changePasswordForm.get('new_password').valueChanges
       .subscribe(_=>{
            this.changePasswordForm.get('confirm_password').updateValueAndValidity()     
    })

Another approach is to create a customValidator for the entire form. Since you are using material, make sure to utilize setErrors. The validator could look like this:

validatorRepeatPassword(form: FormGroup) {
   // Validator logic here
}

Then use it as follows:

this.changePasswordForm = this.formBuilder.group(
  {
    old_password: null,
    new_password: null,
    confirm_password: null,
  },
  { validator: this.validatorRepeatPassword }
);

The final approach involves creating a validator that checks both controls (in this case, new_password and confirm_password). Here's an example function you can use:

matchValidator(field: string, not: boolean = false) {
   // Match validation logic here
}

You can implement it like this:

this.changePasswordForm = this.formBuilder.group(
  {
    old_password: null,
    new_password: [null,this.matchValidator('confirm_password',true)],
    confirm_password: [null,this.matchValidator('confirm_password',true)]
  }
);

Note that you are now able to pass parameters through a function, although this should be adjusted.

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

"Error: Import statement must be used within a module" encountered in TypeScript (with nodemon) and Node.js (running in Docker)

Within the server directory of my web application written in TypeScript, there is a nodemon command used to automatically restart the code after changes are made. The command looks like this: nodemon dist/index.js However, upon running it, an error is enc ...

Production environment experiencing issues with Custom Dashboard functionality for AdminJS

I have successfully integrated AdminJS into my Koa nodejs server and it works perfectly in my local environment. My objective is to override the Dashboard component, which I was able to do without any issues when not running in production mode. However, wh ...

Acquire the URL using Angular within a local environment

I am currently working on a basic Angular project where I have a JSON file containing some data. [{ "name": "Little Collins", "area": "Bronx", "city": "New York", "coverImage": "https://images.unsplash.com/photo-1576808597967-93bd9aaa6bae?ixlib=rb-1.2.1&a ...

Encountering challenges with the search and filtering features

I'm having some trouble with the search and filter features I'm creating. They work fine initially, but once I enter a search query in the input field, the results show up as expected. However, if I delete the query or enter a different one, the ...

The attribute 'split' is not found on the never data type

I have a function that can update a variable called `result`. If `result` is not a string, the function will stop. However, if it is a string, I then apply the `split()` method to the `result` string. This function always runs successfully without crashin ...

Error: The specified path in the MEAN stack must be either a string or Buffer

I am currently utilizing Angular 5 on the front-end, Node for back-end operations, and MongoDB as the database. My current challenge involves attempting to save an image to the database, but I keep encountering an error. Determining whether the issue lies ...

Set the variable value by clicking on another component within *ngFor in Angular 2

I am attempting to use *ngFor to pass an object to another component, but only the last object in the table is being passed. The object that was clicked should be displayed instead. How can I solve this issue? <tr data-toggle="control-sidebar" *ngFor=" ...

Is it possible to determine the type of a class-type instance using class decorators?

Explore this example of faltering: function DecorateClass<T>(instantiate: (...params:any[]) => T){ return (classTarget:T) => { /*...*/ } } @DecorateClass((json:any) => { //This is just an example, the key is to ensure it returns ...

Assign a value to a variable using a function in Typescript

Is there a way in typescript to explicitly indicate that a function is responsible for assigning value to a variable? UPDATED CODE Here, the code has been simplified. While getText() ensures that it will never be undefined, this may not hold true in subs ...

Problem with BehaviorSubject: next() method is not functioning as expected

My goal is to utilize an angular service for storing and communicating data via observables. Below is the implementation of my service: public _currentLegal = new BehaviorSubject({ name: 'init', _id: 'init', country: 'init& ...

Tips for integrating DataTable with Angular 7

Currently, I am in the process of setting up a table to display employees using DataTable. However, upon implementation, I have encountered an issue where the pagination, filtering, and sorting functionalities do not seem to work as expected. Strangely, no ...

How can I make sure that another function will only be executed after the completion of a function in

I'm currently working on an app with Angular CLI, and I am trying to retrieve a list after an insertion. Despite trying various methods such as observer, promise, async, setTimeout, etc., I haven't been able to find the right solution yet. I feel ...

Setting up the NPM configuration in Intellij IDEA for proxy in Angular 2

How can I set up Intellij IDEA to run an npm Angular 2 conf with a proxy as an argument by clicking on it? I know I can do it via the terminal using the command ng serve --proxy-config proxy.conf.json, but it would be much easier to configure it in Intelli ...

"Implementing passport authentication in an Angular application to return JSON data instead of redirecting

Seeking to retrieve JSON data after a successful sign-in or login to utilize Angular for frontend redirection, rather than Express handling the redirect on the backend. I have attempted solutions found here that seem logical and should function according ...

find your way to an angular component within a different module

Currently, I am utilizing this template and running into an issue with navigating from the login component to a different component associated with another module. I have attempted using both this.router.navigate(['myRoute']) and this.router.nav ...

Purge React Query Data By ID

Identify the Issue: I'm facing a challenge with invalidating my GET query to fetch a single user. I have two query keys in my request, fetch-user and id. This poses an issue when updating the user's information using a PATCH request, as the cach ...

Troubleshooting Angular 7 Build Failure: Missing Typescript .d.ts Declaration Files for Ahead-of-Time Compilation

I have encountered difficulties in building my Angular 7 application after upgrading from v6. When I use ng build, everything runs smoothly. However, when I try either ng serve --aot, ng build --aot, or ng build --prod (which also includes aot), an error ...

Designing the File and Folder Organization for Next.js Frontend and AWS Cloud Development Kit (CDK) Backend

When it comes to creating websites with serverless backends, I've been thinking about the best practices for folder structure. Currently, my setup includes a Next.js frontend and an AWS CDK backend. The way I've structured the folders has the bac ...

Retrieve functions contained within the component.ts file of an Angular library: tips and tricks

I have developed an Angular library, named 'mylib', where I have utilized only the mylib.component.ts file. The HTML element codes are included inside the template variable of this file, along with the functions responsible for modifying these el ...

Is it possible to replicate a type in TypeScript using echo?

Is there any equivalent in TypeScript to the following code snippet? type TypeA = { x: number }; printType(TypeA); I have found a method that consistently enables TypeScript to provide a type description. const y = { x: 1, z: 'hello', }; ...