Search code examples
angularangular-reactive-forms

Angular Input validate only on click. reset when user type or remove entire text


i have bellow form input

<form [formGroup]="userForm" novalidate>
  <div class="field">
    <label for="firstName" class="block">First Name</label>
    <input
      type="text"
      pInputText
      placeholder="First Name"
      (change)="clearValidation('firstName')"
      [ngClass]="{'required' : !this.userForm.controls['firstName'].valid && 
                      this.userForm.controls['firstName'].dirty}"
      formControlName="firstName"
    />
  </div>
  <button pButton (click)="addUser()" label="Submit"></button>
</form>

and click function

addUser() {
  if (this.userForm.valid) {     
  } else {
    Object.keys(this.userForm.controls).forEach(field => {
      const control = this.userForm.get(field) ;
      control ? control.markAsDirty({ onlySelf: true }) : false ;
      console.log(control);
    });
  }
}

this scenario. when i type and then remove all the text i typed it shows validation failed. i only want to the validation when i click the addUser button.

validation should reset when i stat typing again.

i try to add bellow function but did not work

clearValidation(name: string) {
  const control = this.userForm.get(name);
  control ? control.markAsDirty({ onlySelf: false }) : false;
  console.log(control);
}

Solution

  • You have to use the parameter updateOn of formGroup to 'submit', by doing the form only evaluates the validation on click of submit button. Note that I am using a button of type submit and moved the save action to ngSubmit, this will give you the desired result. Also please use the validators available in angular reactive forms. Finally, we can use markAllAsTouched to skip the for loop and mark everything as touched at once on submit function.

    import { Component, OnInit } from '@angular/core';
    import { CommonModule } from '@angular/common';
    import { ImportsModule } from './imports';
    import {
      FormControl,
      FormGroup,
      ReactiveFormsModule,
      Validators,
    } from '@angular/forms';
    @Component({
      selector: 'input-text-reactive-forms-demo',
      template: `
        <form [formGroup]="formGroup" (ngSubmit)="addUser()">
          <div class="card">
            <div><input type="text" pInputText formControlName="text" /></div>
            <div *ngIf="formGroup?.get('text') as textCtrl">
              <div *ngIf="textCtrl?.errors?.required && textCtrl?.touched">Field is required</div>
            </div>
          </div>
          <button pButton label="Submit" type="Submit"></button>
        </form>
      `,
      standalone: true,
      styles: [
        `
      ::ng-deep input.ng-invalid.ng-touched {
          border: 1px solid red !important;
      } 
      `,
      ],
      imports: [ImportsModule, ReactiveFormsModule, CommonModule],
    })
    export class InputTextReactiveFormsDemo implements OnInit {
      formGroup: FormGroup | undefined;
    
      ngOnInit() {
        this.formGroup = new FormGroup(
          {
            text: new FormControl<string | null>('', Validators.required),
          },
          {
            updateOn: 'submit',
          }
        );
      }
    
      addUser() {
        if (this.formGroup.invalid) {
          this.formGroup.markAllAsTouched();
          return;
        }
        alert('saving');
      }
    }
    

    Stackblitz Demo