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?

amitairos
  • 2,907
  • 11
  • 50
  • 84

4 Answers4

25

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

user184994
  • 17,791
  • 1
  • 46
  • 52
  • Thanks. Although in my code, the form doesn't clear after calling resetForm. Why is this? – amitairos Jul 01 '18 at 18:46
  • Hard to say without seeing it. Do you get any errors in the console? – user184994 Jul 01 '18 at 18:51
  • Found the bug. I have another form. When I remove it, it works – amitairos Jul 01 '18 at 18:56
  • How do I access only the formGroupDirective of the second form? – amitairos Jul 01 '18 at 19:01
  • 4
    Give it an identifier, such as `#myForm="ngForm"`, and then access it with `@ViewChild('myForm') formGroupDirective: FormGroupDirective;` instead – user184994 Jul 01 '18 at 19:05
  • thanks so much! I have to add that one should not(!) reset the form group. This and not more is needed. – JFFIGK Mar 13 '20 at 19:09
  • 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. – StackOverflowUser Sep 07 '22 at 08:20
  • 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 form – Zoey Oct 07 '22 at 14:52
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();
  }
}
Akitha_MJ
  • 3,882
  • 25
  • 20
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>
Amit Chigadani
  • 28,482
  • 13
  • 80
  • 98
  • 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. – amitairos Jul 01 '18 at 15:34
  • I have added more description onto what will happen, if you clear the validators. Please check that. – Amit Chigadani Jul 01 '18 at 15:36
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

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • Actually, calling reset marks them as pristine anyway – user184994 Jul 01 '18 at 15:56
  • @user184994 good to know, thanks for feedback. But wait, OP is stating that he resets form.. – Antoniossss Jul 01 '18 at 16:00
  • @amitairos 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. – Antoniossss Jul 01 '18 at 16:01
  • @Antoniossss Tried using change detection, and it still shows the errors. – amitairos Jul 01 '18 at 16:06
  • Please create stackblitz for us, it will be much more simpler – Antoniossss Jul 01 '18 at 16:08
  • I can help with that: https://stackblitz.com/edit/angular-idiv9j?file=src%2Fapp%2Fapp.component.ts. 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. – user184994 Jul 01 '18 at 16:14
  • @amitairos thanks to user184994 I have added stackblitz with POC. Works like I described. – Antoniossss Jul 01 '18 at 16:34
  • user - reactive forms has no "submitted" state. It is only interface between UI and data model :) – Antoniossss Jul 01 '18 at 16:43
  • @Antoniossss 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 it – user184994 Jul 01 '18 at 16:52