Angular Reactive Form submit and clear validation
Asked Answered
L

4

7

I have a reactive form

 <form [formGroup]="secondFormGroup">
      <ng-template matStepLabel>enter items</ng-template>
      <div style="display: flex; flex-direction: column;">
        <mat-form-field>
          <input matInput type="text" placeholder="category"  [(ngModel)]="newItem.CategoryName" formControlName="category"
          />
        </mat-form-field>
        <mat-form-field>
          <input matInput type="text" placeholder="sub category"  [(ngModel)]="newItem.SubCategoryName" formControlName="subCategory"
          />
        </mat-form-field>
        <mat-form-field>
          <input matInput type="text" placeholder="product"  [(ngModel)]="newItem.ProductName" formControlName="name"/>
        </mat-form-field>
        <mat-form-field>
          <input matInput  [(ngModel)]="newItem.Amount" type="number" min="0" placeholder="amount" formControlName="amount"
          />
        </mat-form-field>
        <mat-form-field>
          <input matInput  [(ngModel)]="newItem.Price" type="number" min="0" placeholder="price" formControlName="price"
          />
        </mat-form-field>
        <button mat-raised-button color="primary" (click)="AddNewProduct(newItem)" style="float: left; align-self: flex-end;">submit</button>
      </div>
    </form>

I initialize it like this:

 this.secondFormGroup = this._formBuilder.group({
  category: ['', Validators.required],
  subCategory: ['', Validators.required],
  name: ['', Validators.required],
  amount: ['', Validators.required],
  price: ['', Validators.required]
});

Upon clicking sumbit I call this method:

AddNewProduct(newProduct) {
if (this.secondFormGroup.valid) {
  //add product
  this.secondFormGroup.reset();
 } 
}

After adding the product, I clear the form. However, once the form is cleared, it triggers the validation errors. I want the validation errors to show only when the user clicks submit and the form isn't valid, not when I clear the form after submitting.

How can I fix this?

Lento answered 1/7, 2018 at 15:21 Comment(0)
J
26

The issue seems to be that the form is marked as submitted after reset is called. If the form is marked as submitted, regardless of whether or not its pristine, the errors will be highlighted.

You'll need to call resetForm instead, which is on the FormGroupDirective:

@ViewChild(FormGroupDirective) formGroupDirective: FormGroupDirective;

this.formGroupDirective.resetForm();

Secondly, you'll need to wrap it in a setTimeout with a timeout of 0, so that the form is submitted before it resets.

setTimeout(() => this.formGroupDirective.resetForm(), 0)

I've tested this in a StackBlitz, and it all seems to work:

https://stackblitz.com/edit/angular-l6xq1d?file=src%2Fapp%2Fapp.component.ts

Judaize answered 1/7, 2018 at 16:30 Comment(8)
Thanks. Although in my code, the form doesn't clear after calling resetForm. Why is this?Lento
Hard to say without seeing it. Do you get any errors in the console?Judaize
Found the bug. I have another form. When I remove it, it worksLento
How do I access only the formGroupDirective of the second form?Lento
Give it an identifier, such as #myForm="ngForm", and then access it with @ViewChild('myForm') formGroupDirective: FormGroupDirective; insteadJudaize
thanks so much! I have to add that one should not(!) reset the form group. This and not more is needed.Jacquez
For the 1 other dev that MIGHT get value from this: formGroupDirective.resetForm() clears all the form fields and works great to avoid validators triggering. In addition to other fields, I had a mat-radio-group whose state I wanted to maintain - but it was being completely cleared. My solution was, prior to the setTimeout() and resetForm(), I saved the previously-set option value (controlled by a component field) into a local variable and then cleared that component field. After invoking resetForm(), inside the same setTimeout() I restored the option value component field value to what it was.Frontogenesis
this doesn't work for me, although I don't know where you are using that formGroupDirective, in your stackblitz there's no reference to it in the HTML. I thought there would be something like #formGroupDirective="formGroupDirective" on the formLepidote
S
3

This works, try this you need to reset the formDirective otherwise it will not 100% resting the form

Template:

<form 
  ...
  #formDirective="ngForm" 
>

Component:

import { ViewChild, ... } from '@angular/core';
import { NgForm, ... } from '@angular/forms';

export class MyComponent {
 ...
 @ViewChild('formDirective') private formDirective: NgForm;

  constructor(... )

  private someFunction(): void { 
    ...
    formDirective.resetForm();
  }
}
Sheply answered 8/1, 2019 at 14:5 Comment(0)
P
0

You can easily clear the validators of form using clearValidators()

this.secondFormGroup .clearValidators();
this.secondFormGroup .updateValueAndValidity();

But this will remove the validators from the actual form group, and it will not show errors on form submit from the next time.

Better way to do is :

You could simply use flag on the error template, to display the errors based on form submit/reset. And set/reset the flag accordingly.

public formSubmitted = false;

onSubmit(){
   this.formSubmitted = true;
}

reset(){
   this.formSubmitted = false;
}

template file

<div *ngIf="formSubmitted">
 display errors
</div>
Peppers answered 1/7, 2018 at 15:29 Comment(2)
Thanks, but I don't want to just show or hide an element for the error. I want to mark the fields red like the default style does.Lento
I have added more description onto what will happen, if you clear the validators. Please check that.Peppers
P
0

If you are using Angular Material inputs, then you can hide error state by setting inputs as untouched. Material input fields shows error status only if input is touched.

So

this.secondFormGroup.markAsUntouched();

should do the trick.

You may have to initiate change detection run after such operation (depends on scenario)

Here you have proof of concept. Input is initially in error state. Dedicated button clears this state untill future input.

https://stackblitz.com/edit/angular-tadkmb?file=src%2Fapp%2Fapp.component.ts

Pomerleau answered 1/7, 2018 at 15:47 Comment(9)
Actually, calling reset marks them as pristine anywayJudaize
@Judaize good to know, thanks for feedback. But wait, OP is stating that he resets form..Pomerleau
@Lento ofc it work, its just you that dont know how to use it. Stating "not work" means nothing to me as there may be 10000 reasons why it is not working in your case. I can only guess that you need to run change detection like I have stated in last sentence.Pomerleau
@Pomerleau Tried using change detection, and it still shows the errors.Lento
Please create stackblitz for us, it will be much more simplerPomerleau
I can help with that: stackblitz.com/edit/…. The issue seems to be that the form is marked as submitted after reset is called, and that value is never reset. If the form is marked as submitted, regardless of whether or not its pristine, the errors will be highlighted.Judaize
@Lento thanks to user184994 I have added stackblitz with POC. Works like I described.Pomerleau
user - reactive forms has no "submitted" state. It is only interface between UI and data model :)Pomerleau
@Pomerleau It was actually a property on https://angular.io/api/forms/FormGroupDirective, and is being used by the material error checker, as described in https://github.com/angular/material2/issues/7522. As I mentioned in my answer above, calling resetForm in a setTimeout should handle itJudaize

© 2022 - 2024 — McMap. All rights reserved.