Angular 2:表单提交被取消,因为表单未连接。

105
我有一个包含表单的模态框,当销毁该模态框时,控制台会出现以下错误:

表单提交已取消,因为未连接表单

该模态框添加到一个名为<modal-placeholder>的元素中,该元素是<app-root>的直接子元素,而<app-root>是我的顶级元素。

在Angular 2中,正确的方法是从DOM中移除表单并摆脱此错误?我当前使用componentRef.destroy();


1
可能是重复的问题:获得错误"因为表单未连接,表单提交被取消" - Saravana
你是否有一个 *ngIf 来隐藏和显示表单? - mickdev
@mickdev,我没有使用*ngIf,而是通过componentRef.destroy();来销毁模态框。我已经在我的问题中添加了更多细节。谢谢! - nick
2
@mickdev 如果我使用 *ngif 来隐藏和显示表单,我该怎么做? - Jun
11个回答

219

可能还有其他原因导致此问题发生,但在我的情况下,浏览器将一个按钮解释为提交按钮,因此当单击该按钮时,表单被提交导致错误。添加type="button"修复了这个问题。完整元素:

    <button type="button" (click)="submitForm()">

49
我不确定为什么会接受这个答案,因为这样做会失去按回车键提交表单的能力。 - Peter LaBanca
7
Nour的答案是最简单的,也允许使用回车键。 - Heiner
2
这解决了我的问题,我正在实现一个CANCEL按钮到表单中,该按钮通过*ngIf指令从页面中删除表单。我有一个SAVE按钮,触发逻辑也会删除表单(在成功保存时),但即使我没有type ='button',它也不会出现错误消息。 - AlanObject
3
在我的情况下,这个错误发生在一个取消按钮上,所以我很高兴我添加了type="button" :) - Marcos Lima
我认为这个答案很好,因为你应该在表单中明确指出哪个按钮是提交按钮。这解决了错误地使用其他按钮进行提交的问题,并允许您继续使用回车键进行提交。 - Justin
1
如果您正在使用响应式表单,请不要在<button>上放置(click)="onSubmit()",而是在<form>上使用(ngSubmit)="onSubmit()"(请参见Nour的答案)。如果您意外地将(click)处理程序留在按钮上,您将会得到相同的错误。 - Stevethemacguy

107
在表单标签中,您应该写入以下内容:
 <form #myForm="ngForm" (ngSubmit)="onSubmit()">

在表单内部,您应该拥有提交按钮:

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

最重要的是,如果你的表单中有其他按钮,你应该给它们添加type="button"属性。保留默认的type属性(我认为是submit)将会导致警告信息。

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

6
我认为 #myForm="ngForm" 不是必需的。 - Heiner
1
{btsdaf} - Nour
这是解决它的正确方式。这样可以去掉消息,同时保持按回车键提交的能力。 - William Stevens
2
注意:不要在按钮上使用单击处理程序。在我的情况下,我尝试同时使用<form (ngSubmit)="onSubmit()">和<button (click)="onSubmit()">,并且得到了相同的错误。换句话说,如果您正在使用响应式表单,请确保不要使用Erik Lindblad的答案。 - Stevethemacguy

25

今天我遇到了完全相同的问题,但没有使用模态框。在我的表单中,有两个按钮。一个提交表单,另一个在点击时返回上一页。

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

点击具有routerLink的第一个按钮确切地执行了它应该执行的操作,但似乎也试图提交表单,然后在提交过程中必须放弃表单提交,因为表单所在的页面已从DOM中卸载。

这似乎与您遇到的问题完全相同,只是使用的是模态框而不是整个页面。

如果直接指定第二个按钮的类型为除submit以外的其他内容,则问题得到解决。

<button type="button "class="btn btn-default" routerLink="/events">Cancel</button>
所以,如果您通过“取消”按钮或类似物品关闭模态框,则指定该按钮的类型(如上所示)应解决您的问题。

6
在表单元素中,您需要定义提交方法(ngSubmit),类似于: <form id="currency-edit" (ngSubmit)="onSubmit(f.value)" #f="ngForm"> 在提交按钮上,您省略了单击方法,因为您的表单现在连接到了提交方法: <button class="btn btn-success" type="submit">保存</button> 按钮应该是提交类型。
在组件的代码后台中,您实现“onSubmit”方法,例如像这样: onSubmit(value: ICurrency) { ... } 此方法接收一个值对象,其中包含来自表单字段的值。

谢谢,如果您仍然希望在表单中使用button type="submit",那么这应该是被接受的答案。 - Fjut

5

如果在提交表单时伴随着组件的销毁,那么表单提交会在表单从DOM中分离的竞争条件下失败。例如,我们有以下代码:

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

如果saveData是异步的(例如通过API调用保存数据),那么我们可能需要等待结果:
submitForm() {
  this.saveDataAsync().subscribe(
    () => this.abandonForm(),
    (err) => this.processError(err) // may include abandonForm() call
  );
}

如果您需要立即放弃表单,零延迟方法也应该有效。这可以保证在调用表单提交后,DOM分离将在下一个事件循环中完成:
submitForm() {
  this.saveData();
  setTimeout(() => this.abandonForm());
}

无论按钮类型如何,这应该都可以正常工作。

5

我最近遇到了这个问题,event.preventDefault() 对我有用。 将其添加到您的点击事件方法中。

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

并且:

submitForm(event: Event) {
  event.preventDefault();
  // ...
}

2
这个答案缺乏足够的细节。请令人信服地解释这个解决方案与其他已列出的解决方案有何不同或更好。在发布之前,请阅读 SO 指南。 - sparkitny
2
@sparkplug 不要过于严格,这个答案很有用,即使它需要更多的细节。 - Will Shaver
Will Shaver - 也许有用。但格式良好且易于解释的答案并不多见。标准的存在是为了确保答案易于SO用户阅读和理解。@dhilt的答案是更详细、更易于跟随的解决方案的一个例子。 - sparkitny
这对我来说是解决方案,而不是添加 type="button" - Gavin Sutherland

2

我通过添加属性type = "button"解决了这个问题。

<button type="button" onClick={props.formHandler}>Cancel</button>

0

我曾经遇到过这个警告,我把按钮类型从“submit”改成了“button”,问题得到了解决。


0

我在Angular 6中看到了这个问题,即使没有提交按钮。 当同一模板中存在多个表单时会发生这种情况。 不确定是否有解决方案/解决方案是什么。


0
如果您仍然希望保持按钮的功能为“提交”,那么您不应该在该按钮上使用单击事件。相反,您应该在表单上使用ngSubmit事件。
例如:
<form (ngSubmit)="destroyComponent()">
<button type="submit">submit</button>
</form>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接