105

I have a modal that contains a form, when the modal is destroyed I get the following error in the console:

Form submission canceled because the form is not connected

The modal is added to a <modal-placeholder> element which is a direct child to <app-root>, my top level element.

What's the correct way to removing a form from the DOM and getting rid of this error in Angular 2? I currently use componentRef.destroy();

dhilt
  • 18,707
  • 8
  • 70
  • 85
nick
  • 3,521
  • 3
  • 22
  • 32
  • 1
    Possible duplicate of [Getting Error "Form submission canceled because the form is not connected"](http://stackoverflow.com/questions/42053775/getting-error-form-submission-canceled-because-the-form-is-not-connected) – Saravana Mar 01 '17 at 12:04
  • did you have an *ngIf that hide and show the form ? – mickdev Mar 01 '17 at 12:32
  • @mickdev no *ngIf, I destroy the modal like this `componentRef.destroy();`, I've added more details to my question. Thanks! – nick Mar 01 '17 at 13:48
  • 2
    @mickdev what should I do if I use *ngif to hide and show the form – Jun Apr 05 '18 at 17:50

11 Answers11

219

There might be other reasons this occurs but in my case I had a button that was interpreted by the browser as a submit button and hence the form was submitted when the button was clicked causing the error. Adding type="button" fixed the issue. Full element:

    <button type="button" (click)="submitForm()">
Erik Lindblad
  • 2,279
  • 1
  • 10
  • 6
  • 48
    I'm not sure why this answer was accepted, because in doing this, you lose the ability to press enter to submit the form. – Peter LaBanca Jul 03 '17 at 16:55
  • 7
    The answer by Nour is the most simple one and allows enter key. – Heiner Oct 25 '17 at 09:32
  • 2
    This fixed my issue where I was implementing a CANCEL button to the form which removed the form from the page via an *ngIf directive. I have a SAVE button which triggers logic to also remove the form (on successful save) but this error message never appeared with it even though I don't have the type='button'. – AlanObject Feb 11 '18 at 19:57
  • 3
    In my case this error was occurring on a Cancel button, so it is good I added the `type="button"` :) – Marcos Lima Jul 18 '19 at 12:10
  • I think this answer is good in that you should be explicit in your forms as to which button is the submit button. It solves this issue of the wrong button being used for submission as well as allows you to continue to use the enter key for submissions. – Justin Aug 21 '19 at 20:29
  • 1
    If you're using reactive forms, do *not* put (click)="onSubmit()" on the – Stevethemacguy Mar 10 '21 at 04:30
107

In the form tag you should write the following:

 <form #myForm="ngForm" (ngSubmit)="onSubmit()">

and inside the form you should have submit button:

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

And most importantly, if you have any other buttons in your form you should add type="button" to them. Leaving the default type attribute (which I think is submit) will cause the warning message.

<button type="button"></button>
creimers
  • 4,975
  • 4
  • 33
  • 55
Nour
  • 5,609
  • 3
  • 21
  • 24
  • 6
    I think #myForm="ngForm" is not required. – Heiner Oct 24 '17 at 10:16
  • 1
    You are right, unless you need the reference to the ngForm it is not required. – Nour Oct 25 '17 at 06:42
  • This is the correct way to solve it. This gets rid of the message while keeping the ability to submit by pressing enter. – William Stevens Nov 01 '19 at 19:19
  • 2
    Note: make sure you do *not* use a click handler on the button. In my case, I was trying to use both
    *and*
    – Stevethemacguy Mar 10 '21 at 04:34
25

So I actually just ran into the exact same problem today except without a modal involved. In my form, I have two buttons. One that submits the form and one that, when clicked, routes back to the previous page.

<button class="btn btn-default" routerLink="/events">Cancel</button>
<button type="submit" class="btn btn-primary">Submit</button>

Clicking on the first button with the routerLink does exactly what its supposed to, but also apparently tries to submit the form as well, and then has to abandon form submission because the page that the form was on is unmounted from the DOM during submission.

This appears to be the exact same thing that is happening to you, except with a modal instead of the entire page.

The problem becomes fixed if you directly specify the type of the second button to be something other than submit.

<button type="button "class="btn btn-default" routerLink="/events">Cancel</button>

So if you are closing the modal via a 'Cancel' button or something of the sort, specifying that button's type, as shown above, should solve your issue.

Darkrender
  • 251
  • 3
  • 3
6

In the form element you need to define submit method (ngSubmit), something like: <form id="currency-edit" (ngSubmit)="onSubmit(f.value)" #f="ngForm">

and on the submit button you omit click method, because your form is now connected to the submit method: <button class="btn btn-success" type="submit">Save</button> The button should be of submit type.

In the code behind component you implement "onSubmit" method, for example something like this: onSubmit(value: ICurrency) { ... } This method is receiving an value object with values from the form fields.

user6600768
  • 163
  • 1
  • 8
  • Thanks, this should be the accepted answer if you still want to use button type="submit" on your form – Fjut Oct 17 '17 at 14:52
5

In case that submitting the Form is being accompanied by the component's destroying, the Form submitting fails in race condition with the detaching of the Form from the DOM. Say, we have

submitForm() {
  if (this.myForm.invalid) {
    return;
  }
  this.saveData(); // processing Form data
  this.abandonForm(); // change route, close modal, partial template ngIf-destroying etc
}

If saveData is async (for example it saves the data via API call) then we may wait for the result:

submitForm() {
  this.saveDataAsync().subscribe(
    () => this.abandonForm(),
    (err) => this.processError(err) // may include abandonForm() call
  );
}

If you need to abandon the Form immediately, a zero-delay approach also should work. This guarantees the DOM detachment to be in the next event loop after the Form submission has been called:

submitForm() {
  this.saveData();
  setTimeout(() => this.abandonForm());
}

This should work regardless of the button type.

dhilt
  • 18,707
  • 8
  • 70
  • 85
5

I had this problem recently and event.preventDefault() worked for me. Add it to your click event method.

<button type="submit" (click)="submitForm($event)" mat-raised-button>Save</button>

And:

submitForm(event: Event) {
  event.preventDefault();
  // ...
}
Vukašin Manojlović
  • 3,717
  • 3
  • 19
  • 31
  • 2
    There is not enough detail to this answer. Please explain convincingly how this solution is different or better than the other ones listed as this post already has several solutions. Please read the SO guidelines before posting. – sparkitny Apr 10 '18 at 00:16
  • 2
    @sparkplug don't gatekeep, this answer was useful, even if it needed more detail. – Will Shaver Jun 17 '19 at 16:49
  • Will Shaver - Useful, maybe. Well formatted and easy to interpret, not so much. Standards are in place to ensure answers are easy for a SO user to read and understand. The answer by @dhilt is an example of a solution in more detail that is easier to follow. – sparkitny Jun 18 '19 at 01:24
  • This was the solution for me rather than adding `type="button"` – Gavin Sutherland Nov 01 '21 at 15:45
2

I resolved the issue by adding the attribute type = "button".

<button type="button" onClick={props.formHandler}>Cancel</button>
bad_coder
  • 11,289
  • 20
  • 44
  • 72
Abd
  • 85
  • 7
0

I see this in Angular 6, even with no submit buttons at all. happens when there are multiple forms in the same template. not sure if there's a solution / what the solution is.

Nir
  • 1,225
  • 12
  • 8
0

i had this warning, i changed button type "submit" to "button" problem solved.

Shahid Islam
  • 559
  • 3
  • 7
0

If you still want to maintain the functionality of the button to be of type "submit", then you should not be using the click event on that button. Instead you should use the ngSubmit event on the form.

Example:

<form (ngSubmit)="destroyComponent()">
<button type="submit">submit</button>
</form>
Snackdex
  • 674
  • 8
  • 18
-1

Maybe you are routing to some other page on your form submission. Use programmatic route navigation, as in the example that follows, rather than passing routerlink into the template:

router.navigate(['/your/router/path'])

Sean Mickey
  • 7,618
  • 2
  • 32
  • 58