Open Nathan-Ryan opened 7 years ago
Have the same issue 😢
plunker repro: http://plnkr.co/edit/UguaoP1sTR85pyZLh2TN?p=preview
It looks like this is just a matter of putting type="reset"
on your button. Without it, the form is marked as submitted which causes the error styling to show up. see: http://plnkr.co/edit/IUhbPom8FnauivHUW3bU?p=preview
@mmalerba trying to understand how this would fix the issue for a button already type="submit".
I'm resetting after the form is submitted and a response has been received back from the server in an observable complete block.
i.e., submitForm() .subscribe( res => store.dispatch(type: foo, res), e => log(e), () => form.reset()); <- still leaving the form inputs as invalid
@goelinsights sounds like maybe a forms issue (could be related to https://github.com/angular/angular/issues/15741). The md-input-container
logic is correct, so there's nothing for material to do here
Not sure why, using resetForm() method fixed this issue for me.
@mmalerba not sure i agree with your diagnosis. I am experiencing same issues and have only updated from material-beta2 to material-beta3. Main angular libraries remain unchanged and problem has only been introduced since material upgrade.
It looks like this is just a matter of putting type="reset" on your button. Without it, the form is marked as submitted which causes the error styling to show up.
after form is submitted, error styling should definitely be removed.
@mmalerba Why is this issue closed? The problem still exists when reseting the formGroup like explained by @goelinsights
Scenario: Press submit button Do some stuff with the data Then call formGroup.reset()
formGroup.reset() does NOT remove mat-input-invalid class
@jeroenvanagt try this
<form [formGroup]="myFormGroup" #f="ngForm">
...
</form>
@ViewChild('f') myNgForm;
reset() {
this.myNgForm.resetForm();
}
@willshowell,
I understand that a reset button works. However, in my case I want to use a submit button, send the data to the backend server and then reset the form (so a new invite can be created).
For the reset, I use :
this.form.reset()
where form is a formGroup
I now use the following workaround
this.form.reset()
Object.keys(this.form.controls).forEach(key => {
this.form.controls[key].setErrors(null)
});
@jeroenvanagt Error state is calculated like this:
isInvalid && (isTouched || isSubmitted)
Unfortunately, resetting the FormGroup isn't enough. You'll need to reset the submitted state of the actual form.
To do that, you need to get access to the FormGroupDirective which binds the FormGroup to the form and then call resetForm()
instead of reset()
.
<form [formGroup]="fg">
...
</form>
@ViewChild(FormGroupDirective) myForm;
sendDataToBackendAndResetForm() {
// TODO: send data to backend
if (this.myForm) {
this.myForm.resetForm();
}
}
See this updated plunker for an example
@mmalerba I don't think we can call a workaround a resolution. This still is not fixed.
Why can't the FormGroup.reset()
method use the FormGroupDirective
to clear the submitted state of the form element?
@Nathan-Ryan The FormGroup
and FormGroupDirective
are part of angular core, not angular material. If you want to request changes to the behavior you can file an issue with https://github.com/angular/angular
@mmalerba the hacky workaround is just to manually remove .mat-input-invalid on submission. If that's the desired approach, we should put it into the docs as it's a fairly straightforward way to address what should be a common problem for a reusable form that is reset on submission (that from my perspective isn't an expected or obvious output).
On Wed, Jun 21, 2017 at 12:01 PM, mmalerba notifications@github.com wrote:
@Nathan-Ryan https://github.com/nathan-ryan The FormGroup and FormGroupDirective are part of angular core, not angular material. If you want to request changes to the behavior you can file an issue with https://github.com/angular/angular
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/angular/material2/issues/4190#issuecomment-310174269, or mute the thread https://github.com/notifications/unsubscribe-auth/ACv1DSsUuegP-lRLkdGOj5o1CoY8DEAUks5sGWh_gaJpZM4NDvLu .
--
Vijay Goel, M.D. Principal, Goel Insights 310-492-5601 www.goelinsights.com
@goelinsights I may be mistaken but manually removing classes is not the recommended workaround. I'll summarize here:
Submitted state is based on the FormGroupDirective
or the NgForm
(depending on if you're using template- or model-driven forms). FormGroup
does not hold submitted state.
If you wish to reset the form, you must gain access to the FormGroupDirective
or the NgForm
and call resetForm()
on it. That will remove .mat-input-invalid
from the input and all associated md-error
s
This behavior is in Angular core, not material. You are welcome to propose a change to the behavior, but that should be done in the angular core repository, not here.
If you simply don't want .mat-input-invalid
to depend at all on submitted state, you will be able to purpose https://github.com/angular/material2/pull/4750 for that once it lands.
Any Update on this fix?
The simplest solution isn't resetting the form afterwards, but preventing the form from being submitted in the first place. You can do that by putting a type="button"
on the button element, so something like this works as expected in my project:
<button type="button" mat-raised-button (click)="form.reset()">
reset
</button>
I think @biowaffeln's answer is the way to go. Simply avoid all references to "Submit" and you're good. To expand on his example:
Before:
<form [formGroup]="createForm" class="create-form" (ngSubmit)="submitForm()">
<button type="submit" mat-raised-button color="primary" [disabled]="createForm.pristine">Create</button>
</form>
After:
<form [formGroup]="createForm" class="create-form">
<button (click)="submitForm()" type="button" mat-raised-button color="primary" [disabled]="createForm.pristine">Create</button>
</form>
Your submit function doesn't accept any arguments, it will simply access form values via the class property, so it doesn't make a difference either way:
submitForm() {
this.myEventEmitter.emit(this.createForm.value)
}
@jplew an advantage of using (ngSubmit) on form is that the form is automatically submitted when you press Enter in a text field. You would need to do that manually.
@NaveenJayaram94 created an infinite loop
Actually this is still a bug only in material. It has nothing to do with resetting the submit state.
In angular core i can put markAsPristine and markAsUntouched on a single formControl. The css classes get set correctly ignoring if it was submitted or not.
The question is why put css class mat-form-field-invalid on it, when there is already ng-invalid. The "red-state" could be calculated like this: ng-invalid && ng-touched finish, it would work.
Bug, feature request, or proposal:
Bug
What is the expected behavior?
Upon resetting a FormGroup, I would expect the visual state of the form to be reset also.
What is the current behavior?
The form group and controls are reset but the mat-input-invalid class remains on the md-input-container suggesting that the control is invalid.
What are the steps to reproduce?
This only seems to happen when the [formGroup] attribute is on a form tag. Works as expected on a div tag.
Create component with a FormGroup and a FormControl with Validators.required . Create a form tag with the [formGroup] attribute. Add an input control to the form with a required attribute.
When running, fill out the form so its valid, then reset the form and model through the click handler on a button. The required control will now have the mat-input-invalid class.
Which versions of Angular, Material, OS, browsers are affected?
Angular 4.0.1 Material 2.0.0-beta.3 Windows 10 Chrome 57
I am also having this issue after reset the form controls are reset but mat-errors are showing invalid
There could be some change detection issue with the mat-form-field-invalid
class. I'll reopen for investigation
Will the problem be solved in the next 1 - 2 releases? Since the problem already exists since 2017?
bump
I love the "not my department" attitude here. The workaround mentioned in this stackoverflow answer should be the default behavior
https://stackoverflow.com/questions/48216330/angular-5-formgroup-reset-doesnt-reset-validators
Versions: "@angular/animations": "^7.2.2", "@angular/cdk": "^7.3.2", "@angular/common": "^7.2.4", "@angular/compiler": "^7.2.4", "@angular/core": "^7.2.4", "@angular/forms": "^7.2.4", "@angular/material": "^7.3.2"
This work for me, for this scenario; I have and material stepper and the user can start de process if he likes, then before show the first step I reset de form calling form():
template:
<form [formGroup]="formGroup"> <button type="button" (click)="submitForm()">
ts:
ngOnInit() { this.formGroup = this._formBuilder.group(new MyForm());
}
submitForm() {
let control: AbstractControl = null; Object.keys(this.formGroup.controls).forEach((name) => { control = this.formGroup.controls[name]; control.updateValueAndValidity(); });
}
reset() { let control: AbstractControl = null; this.formGroup.reset(new DatosGeneralesForm());
setTimeout(() => {
this.formGroup.markAsUntouched();
Object.keys(this.formGroup.controls).forEach((name) => {
control = this.formGroup.controls[name];
control.reset();
control.setErrors(null);
});
}, 100);
}
it seems this is still an issue.
the workaround from @willshowell worked for me, but had to go through some research to get this fixed. Thinking it could be fixed with alternatives already provided here, or at least better documented.
I now use the following workaround
this.form.reset() Object.keys(this.form.controls).forEach(key => { this.form.controls[key].setErrors(null) });
This worked for me. Thanks
@emadkheiralla, while that works for a 1 level structure, it won't work for nested controls. You would need to create a recursive function for that. It also is not recommended, see https://github.com/angular/material2/issues/4190#issuecomment-311488176.
Same problem here.
Same Problem here
Guys try this.
<form` [formGroup]="someFormGorup" (ngSubmit)="onSubmitFunction($event)">
...
</form>
onSubmitFunction(event) {
// TODO: some code
event.currentTarget.reset()
this.someFormGorup.reset()
}
Guys try this.
<form` [formGroup]="someFormGorup" (ngSubmit)="onSubmitFunction($event)"> ... </form> onSubmitFunction(event) { // TODO: some code event.currentTarget.reset() this.someFormGorup.reset() }
This worked for me. Thanks
I had the same problem but with a single FormControl() without a FormGroup. After .reset() and .setErrors(null) the validator stops working until .updateValueAndValidity(); So basically it is: someControl.reset() someControl.setErrors(null) someControl.updateValueAndValidity();
I think when you are using FormGroup you'll need someFormGroup.updateValueAndValidity()...
I found that after calling resetForm() and reset(), submitted was not being reset and remained as true, causing error messages to display. This solution worked for me. I found it while looking for a solution to calling select() and focus() on an input tag, which also wasn't working as expected. Just wrap your lines in a setTimeout(). It's a bit of a hack, but does the trick.
<form [formGroup]="myFormGroup" #myForm="ngForm">
…
<button mat-raised-button (click)="submitForm()">
</form>
submitForm() {
…
setTimeout(() => {
this.myForm.resetForm();
this.myFormGroup.reset();
}, 0);
}
@hfournier have you tried updateValueAndValidity()?
@hfournier have you tried updateValueAndValidity()?
@sapabg Yes. It didn't work.
this might help: https://stackblitz.com/edit/angular-nxuztu
It looks like this is just a matter of putting
type="reset"
on your button. Without it, the form is marked as submitted which causes the error styling to show up. see: http://plnkr.co/edit/IUhbPom8FnauivHUW3bU?p=preview
Thanks. this solves my problem.
I found that after calling resetForm() and reset(), submitted was not being reset and remained as true, causing error messages to display. This solution worked for me. I found it while looking for a solution to calling select() and focus() on an input tag, which also wasn't working as expected. Just wrap your lines in a setTimeout(). It's a bit of a hack, but does the trick.
Did not help.
But this helped me:
Guys try this.
<form` [formGroup]="someFormGorup" (ngSubmit)="onSubmitFunction($event)"> ... </form> onSubmitFunction(event) { // TODO: some code event.currentTarget.reset() this.someFormGorup.reset() }
Angular 9 this problem still exists!
I experienced this issue. my only hack was to set
submitted = false;
postComment(id ) {
this.submitted = true;
if (this.commentForm.invalid) {
return;
}
this.postService.sendComment(this.id, this.commentForm.value).subscribe(data => {
console.log(data);
this.submitted = false; // make submitted false again
}, err => {
console.log('error occurred here', err);
});
this.commentForm.reset();
}
The above code works for me
I think resetting the directive should be the default behavior of a form field. The issue is open for 3 years, is there any progress so far?
TL;dr: use <form novalidate>
or you're gonna have a bad time.
So, I was feeling pretty salty about this behavior. Why is this clearly wrong yet nobody is budging? It seemed to me like one of the following should be true:
submitted
state with FormGroup#reset()
.submitted
state from FormGroup
.submitted
at all, since it's not part of FormGroup
et al.Well, this is just one of those things where everyone is kinda doing the right thing. If you wound up here, what nobody's saying is that the DOM is crazy and your HTML is wrong (MDN):
Note that the submit event fires on the
<form>
element itself, and not on any<button>
or<input type="submit">
inside it. However, theSubmitEvent
which is sent to indicate the form's submit action has been triggered includes asubmitter
property, which is the button that was invoked to trigger the submit request.The submit event fires when the user clicks a submit button (
<button>
or<input type="submit">
) or presses Enter while editing a field (e.g.<input type="text">
) in a form. The event is not sent to the form when calling theform.submit()
method directly.Note: Trying to submit a form that does not pass validation triggers an invalid event. In this case, the validation prevents form submission, and thus there is no submit event.
All of that is to say, if you are using <button>
, you are declaring a SUBMIT button, because type="submit"
is the default on the <button>
tag. If you omitted the novaldiation attribute, then the form IS invalid, you have just attempted to submit it, submitting has provoked form validation per the spec, and the control element has no freaking idea because, you know, the DOM.
Now, why is your HTML wrong? Three reasons:
<button>
defaults, you just submitted the form and form submission is a DOM event handled by the <form>
element and wrapped by the NgForm
directive. You should use novalidate on your <form>
to avoid this entire problem in the first place.novalidate
option.novalidate
.The FormGroup really has no idea about any of this because the FormGroup is a pure Angular construct that has nothing to do with DOM APIs. The FormGroupDirective knows about it because it's the jerk that actually talks to the DOM. And now our helpful little mat-form-field comes a long, brings them together, and tells us the form is invalid, which is true! That happened! Yet nobody knows about that submit
event except the mat-form-field
and the FormGroupDirective
it asked.
So, if you can't add novalidate
for some reason and you want a button that doesn't submit your form, you should use one of the following:
<button mat-button type="button">Button Label</button>
<button mat-button formnovalidate>Button Label</button>
(formnovalidate (MDN)).<input mat-button type="button" value="Button Label">
That still doesn't solve the Enter problem, so either handle that as well or just use novalidate
.
Okay, what if you really want to lean on the native submit
/invalid
event cycle for some reason? ONLY the NgForm
has direct knowledge about submit state, so you need to get a handle on it. You can either inject NgForm in your component (constructor(private form: NgForm){}
) or get a handle on a FormGroupDirective
that knows how to talk to it (@ViewChild(FormGroupDirective) formGroupDirective
). You can then ask it to reset the DOM's form object with resetForm()
. That's why you can't just reset()
your ReactiveForms AbstractControls: you have to take it up with the DOM.
Guys try this.
<form` [formGroup]="someFormGorup" (ngSubmit)="onSubmitFunction($event)"> ... </form> onSubmitFunction(event) { // TODO: some code event.currentTarget.reset() this.someFormGorup.reset() }
I have tried many methods, include
FormGroupDirective
, don't work.
this worked for me! 😄
but why ? 🤔
Guys try this.
<form` [formGroup]="someFormGorup" (ngSubmit)="onSubmitFunction($event)"> ... </form> onSubmitFunction(event) { // TODO: some code event.currentTarget.reset() this.someFormGorup.reset() }
I have tried many methods, include
FormGroupDirective
, don't work.this worked for me! 😄
but why ? 🤔
I think (and I'm honestly not positive, I'm still learning a lot of this) the $event of ngSubmit is a wrapper to prevent the html form element's default submit event from firing and triggering an HTTP post.
currentTarget is the HTML form, and uses the DOM reset() rather than the FormGroup reset().
I can't believe the issue is still open from 2017 to this day!
why do I need to create an ngFormDirective
just to reset it?
myFormGroup.reset()
should have made it untouched and clean the validators.
Bug, feature request, or proposal:
Bug
What is the expected behavior?
Upon resetting a FormGroup, I would expect the visual state of the form to be reset also.
What is the current behavior?
The form group and controls are reset but the mat-input-invalid class remains on the md-input-container suggesting that the control is invalid.
What are the steps to reproduce?
This only seems to happen when the [formGroup] attribute is on a form tag. Works as expected on a div tag.
Create component with a FormGroup and a FormControl with Validators.required . Create a form tag with the [formGroup] attribute. Add an input control to the form with a required attribute.
When running, fill out the form so its valid, then reset the form and model through the click handler on a button. The required control will now have the mat-input-invalid class.
Which versions of Angular, Material, OS, browsers are affected?
Angular 4.0.1 Material 2.0.0-beta.3 Windows 10 Chrome 57