Angular Material: Reseting reactiveform shows validation error
Asked Answered
C

6

20

I am using angular5 reactivemodule to show a form in my application. I had also used required validator which will subsequently make the field in red color and show an error msg to the user.

It is working as expected but when I reset the form using

this.form.reset()

the form shows me a validation error that the specific field is required. I also used form.markAsPristine() or form.markAsUntouched() to make it work but the problem persist after applying multiple combination of possible pairs.

example.html

<form [formGroup]="checkForm" (ngSubmit)="submitForm()">
  <mat-form-field>
    <input matInput formControlName="name" placeholder="name" />
    <mat-error *ngIf="checkForm.get('name').errors?.required">
      Name is required.
    </mat-error>
  </mat-form-field>
  <mat-form-field>
    <input matInput formControlName="email" placeholder="email" />
    <mat-error *ngIf="checkForm.get('email').errors?.required">
      Name is required.
    </mat-error>
  </mat-form-field>
  <button [disabled]="checkForm.invalid" type="submit">add</button>
</form>

example.ts

checkForm  = this.formBuilder.group({
  'name': ['', Validators.required],
  'email': ['', Validators.required]
});

submitForm() {
   this.checkForm.reset();
   // this.checkForm.markAsPristine();
   this.checkForm.markAsUntouched();      
}

Any help is appreciated.

Contemplative answered 12/4, 2018 at 4:51 Comment(0)
H
35

By default, Angular/Material watch formControl's error state not only by touched but also submitted status of the form, see below source code.

isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
  return !!(control && control.invalid && (control.touched || (form && form.submitted)));
                                                                       ^^^^^^^^^^^^^^
}

For reason above, you also need to reset the form to unsubmitted status.


You can call resetForm of FormGroupDirective(getting instance by ViewChild) for it will reset both the form data and submit status.

<form #form="ngForm" [formGroup]="checkForm" (ngSubmit)="submitForm(form)">
  ...
</form>

@ViewChild('form') form;

submitForm() {
  this.form.resetForm();
  ...
}

You can also overwrite the default one via implementing ErrorStateMatcher with custom conditions such as ignore submitted status of the form, and apply it on material components.

<mat-form-field>
  <input matInput formControlName="name" placeholder="name" [errorStateMatcher]="errorMatcher" />
  <mat-error *ngIf="checkForm.get('name').errors?.required">
    Name is required.
  </mat-error>
</mat-form-field>

// define custom ErrorStateMatcher
export class CustomErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(control: FormControl, form: NgForm | FormGroupDirective | null) {
    return control && control.invalid && control.touched;
  }
}

// component code
@Component({...})
export class CustomComponent {
  // create instance of custom ErrorStateMatcher
  errorMatcher = new CustomErrorStateMatcher();
}

see fixed demo.

Highbinder answered 12/4, 2018 at 5:58 Comment(10)
Thanks for the solution. In the return statement of isErrorState(), both touch and form submitted are connected by "or" operator so only one of them need to be true at one point of time. I think builtIn function "checkForm.reset()" internally untouched, pristine all the fields.Contemplative
@Contemplative Mention expression (control.touched || (form && form.submitted), either touched or form submitted will turn above expression to true.Highbinder
I am facing issues with above code. It show fields after focussing on them. Any hint would be helpful.Contemplative
Fields are hidden in starting(similar to invisible). Shown only when user focusses on them.Contemplative
@Contemplative I didn't see it in the demo I provided. Maybe you forgot to set placeholder for them?Highbinder
the issue exist after removing the specified code. Code was working fine few days back. I started locating this issue from yesterday. placeholder is placed in it's correct place.Contemplative
@Contemplative can you reproduce you problem with the demo I provided?Highbinder
Thanks for your answer! you saved my day! just two additions to the answer: 1 - You can do @ViewChild(FormGroupDirective) form: FormGroupDirective instead of using a template variable 2 - You could also override Angular Material ErrorStateMatcher to prevent displaying error when form is submittedMultiplex
@Multiplex thank you for the new information, I'll add those info when I come back to computer.Highbinder
this is the only solution wich worked for me, thanks a lot !Warble
M
19

All you need to do is avoid (ngSubmit) method on your reactive form:
1. Remove (ngSubmit)="submitForm()" from your form tag
1. Change your form button type from 'submit' to 'button'
2. On this button you want to set a click action to (click)="submitForm()"
3. in the submitForm() method do:

this.checkForm.markAsPristine();
this.checkForm.markAsUntouched();

This will submit the form and reset its value without alerting validators

Madelainemadeleine answered 23/6, 2018 at 17:49 Comment(3)
I do not recommend this approach, since Form could be submitted in other ways besides click of submit button. What about Keyboard enter key in a single-textbox form?Dactylic
For keyboard submission you can attach an event listener for keydown and execute submission if form is in focus and Enter was pressed. You can work around to achieve you goals, but please feel free to suggest another approachMadelainemadeleine
@AlexOleksiiuk That's hack upon hack.Palmar
C
3

Adding type="reset" to Reset button worked for me instead of using formGroupDirective.resetform().

Convexoconcave answered 14/2, 2022 at 7:17 Comment(1)
Only this is working in Angular 13. I tried all the below methods like using 1. formGroupDirective like below (#formGroupDirective="ngForm") 2. I used resetForm() 3. I used prestine and untouched. 4. loop over the form controls and setvalidators to null. nothing worked.Nonnah
B
1

I has the same issue to reset my formGroup and I take some of Alex Oleksiiuk solution, but I agree with H Dog because submitted only works on click. Finally, this was my solution:

  1. Don't use ngSubmit directive, insted use declare a variable:

Template: <form [formGroup]="formProduct" #formDirective="ngForm">

Controller: @ViewChild('formDirective') private formDirective: NgForm;

  1. Set reset method

    resetForm() { this.formProduct.reset(); ...// }

  2. Up to this point, the submit works and no longer show validation erros. But, if you press reset (cancel, remove, clear...) botton show again the error. To solve this, just put type="button" in your button tag.

<button mat-raised-button 
  (click)="save()"
  [disabled]="!formProduct.valid">
  Save
</button>

<button mat-raised-button
  (click)="resetFormProduct()"
  type="button" 
  color="warn">
  Clear
</button>
Burdelle answered 18/5, 2020 at 5:44 Comment(0)
H
1

An easier way, without using @ViewChild is to set up your HTML like this:

<form [formGroup]="form" #formGroupDirective="ngForm" (ngSubmit)="submit(form, formGroupDirective)">

then in your component you do

submit(form: FormGroup, formGroupDirective: FormGroupDirective): void {
  form.reset();
  formGroupDirective.resetForm();
}

Tested and working for me!

Hora answered 12/11, 2021 at 15:17 Comment(0)
C
0

I tried all the ways to reset the form and its validators. But i couldn't achieve this. I wonder this is issue still open on GitHub https://github.com/angular/components/issues/4190.

Ways that I tried:

 1. this.myForm.markAsPristine();
 2. this.myForm.marskAsUntouched();

Also, I tried to use these:

 1. this.myForm.reset();
 2. this.myFormDirective.resetForm();

Then I tried to reload the same component using below code snippet without reloading the whole page:

this.router.navigateByURL('/', { skipLocationChange: true }).then(() => {
     this.router.navigate([window.location.pathname]);
});

In this way, I am able to move my form to its initial state. I hope it will help someone.

Colston answered 9/11, 2022 at 7:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.