Guruprasad J Rao
Guruprasad J Rao

Reputation: 29683

Angular 5 - Reactive forms doesn't validate form on submit

I have a simple form as below:

some.component.html

<form class="example-form" novalidate (ngSubmit)="onSubmit()" autocomplete="off" [formGroup]="testform">
     <input type="text" formControlName="name" class="form-control" placeholder="Enter name" required/>
     <app-show-errors [control]="claimform.controls.name"></app-show-errors>
     <button type="submit" (click)="onSubmit()">Next</button>
</form>

some.component.ts

ngOnInit() {
    this.testform= new FormGroup({
      name: new FormControl('', { validators: Validators.required})
    }, {updateOn: 'submit'});
}

onSubmit() {
    if (this.testform.valid) {
      alert('saving data');
    } else {
      this._validationService.validateAllFormFields(this.testform);
    }
}

validationService.ts

validateAllFormFields(formGroup: FormGroup) {
    Object.keys(formGroup.controls).forEach(field => {
      const control = formGroup.get(field);
      if (control instanceof FormControl) {
        control.markAsTouched({ onlySelf: true });
      } else if (control instanceof FormGroup) {
        this.validateAllFormFields(control);
      }
    });
}

Reference


Problem

The form will validate on submit if left blank, but even after filling the value when I check this.testform.valid it returns false. But if I remove updateOn:'submit' on form then it validates on blur of input control and when value is entered it validates form return true. Not sure if updateOn is working fine or not or whether I've implemented this in a proper way. Could someone point me in the right direction.

Upvotes: 3

Views: 7747

Answers (1)

Andriy
Andriy

Reputation: 15462

in your HTML you have two calls to onSubmit() function, from submit button:

<button type="submit" (click)="onSubmit()">Next</button>

and from the form:

<form class="example-form" 
      ovalidate 
      (ngSubmit)="onSubmit()" 
      autocomplete="off" 
      [formGroup]="testform">

The first call to be triggered is the button's trigger, which actually does nothing in terms of updating your reactive form, since you set FormGroup's option to {updateOn: 'submit'}. The second call to be triggered is the form's trigger, which does actual form update.

Here is FormGroup directive config:

@Directive({
  selector: '[formGroup]',
  providers: [formDirectiveProvider],
  host: {'(submit)': 'onSubmit($event)', '(reset)': 'onReset()'},
  exportAs: 'ngForm'
})

as we can see in host property DOM form's submit (triggered by hitting ENTER while focused within form or clicking form's submit button) will call onSubmit() function:

onSubmit($event: Event): boolean {
  (this as{submitted: boolean}).submitted = true;
  syncPendingControls(this.form, this.directives);
  this.ngSubmit.emit($event);
  return false;
}

which then will call syncPendingControls() function:

export function syncPendingControls(form: FormGroup, directives: NgControl[]): void {
  form._syncPendingControls();
  directives.forEach(dir => {
    const control = dir.control as FormControl;
    if (control.updateOn === 'submit' && control._pendingChange) {
      dir.viewToModelUpdate(control._pendingValue);
      control._pendingChange = false;
    }
  });
}

which updates a model at last.

So, in your case, just remove (click)="onSubmit()" from the submit button:

<button type="submit">Next</button>

also you do not need required DOM element property on your input, since you set it using Reactive Forms API validators: Validators.required and since you set your form to novalidate which cancels HTML5 form validation.

Upvotes: 5

Related Questions