Javascript 如何在表单提交中获取按钮元素

Javascript 如何在表单提交中获取按钮元素,javascript,angular,Javascript,Angular,我有一个页面上有多个表单。每个表单上都有许多按钮。我想在按下按钮后在按钮上实现一个加载微调器。当我使用普通点击事件时,我可以通过按钮传递: HTML 在这种情况下,button元素被传递,您可以访问它,以便向button添加加载类 但是,如果您使用“提交”按钮尝试相同的操作,它会显示为“未定义”: HTML 在这种情况下,按钮是未定义的,因为按钮上的*ngIf将其从表单范围中屏蔽。我可以删除*ngIf并隐藏按钮,但这会将按钮留在DOM上,我不想这样做 下面是一个堆栈闪电战: 我曾尝试向save按

我有一个页面上有多个表单。每个表单上都有许多按钮。我想在按下按钮后在按钮上实现一个加载微调器。当我使用普通点击事件时,我可以通过按钮传递:

HTML

在这种情况下,button元素被传递,您可以访问它,以便向button添加加载类

但是,如果您使用“提交”按钮尝试相同的操作,它会显示为“未定义”:

HTML

在这种情况下,按钮是未定义的,因为按钮上的
*ngIf
将其从表单范围中屏蔽。我可以删除
*ngIf
并隐藏按钮,但这会将按钮留在DOM上,我不想这样做

下面是一个堆栈闪电战:

我曾尝试向save按钮添加一个附加的click事件,以将按钮设置为loading,但click事件首先触发,并将按钮设置为disabled,然后阻止调用submit事件

我查看了提交事件,但看不到任何链接回单击的按钮的内容


有什么建议吗?

不要使用表单上的
ngSubmit
事件处理程序,而是使用
单击保存按钮上的
事件处理程序。将类型保留为
submit
,这样当用户使用输入控件上的
Enter
键提交表单时,该类型仍然有效

<form #formElement="ngForm">
    ...
    <button #saveButton (click)="save(saveButton, formElement)" type="submit" ...>
        <mat-spinner ...></mat-spinner>
        Save
    </button>
</form>
form{display:none;}

...
取消


拯救
对于您的情况,您不应该将元素传递给函数,然后在其上操作类,而应该简单地维护一个用于加载状态的变量。在组件中,将其初始化为

loading: boolean = false;
在模板中,将该类绑定为

[class.loading]="loading"
在方法中,首先将此属性设置为true,然后在异步调用完成后将其设置为false。类似地,使用相同的变量将禁用的属性设置为

[disabled]="loading"

更新我现在了解您的具体问题。问题在于按钮上的
*ngIf
。它打破了参照系。将其更改为
[隐藏]
,它应该可以工作。以下是最新的StackBlitz:

至于发生的原因,我认为这很好地描述了这个问题:

原始答复:

我甚至都不会把它传过去。只需在类中添加以下内容:

 @ViewChild('saveButton') button;
然后,您可以在保存方法中引用它:

save() {
    console.log(this.saveButton);
}

但我还要补充一点,从插值调用函数不是一个好主意,因为它可能会导致性能问题。相反,您应该订阅设置属性的事件,然后在视图中引用该属性。这样,只在事件触发时调用函数,而不是每次呈现页面时调用函数。

这实际上与提交函数无关,而是与角度和结构指令有关。应用结构指令(
ngFor
ngIf
…)时,angular在引擎盖下的作用是创建
ng模板
节点。这意味着,structural指令范围内定义的模板引用变量仅在该节点中可用

那么,你这里有什么:

<button #saveButton *ngIf="hasSave">
  Save
</button>
<button #cancelButton *ngIf="hasCancel" (click)="clickEvent(cancelButton)">
  Cancel
</button>
单击事件位于按钮上,因此
cancelButton
模板参考变量可用于该事件


使用
hidden
代替另一个答案中建议的
ngIf
,解决了这个问题,因为我们。。那么,隐藏元素。

tl;dr以下是我正在实施的解决方案:


编辑:正如我刚才注意到的,@AJT_82很好地解释了OP在引用元素上的原始问题。因此,我现在删除了我先前的答案


然而,我会建议以下解决方案,该解决方案更适合于关注点分离以角度做事,即引入两个新成员
cancelActive
submitive
,您将能够更灵活地处理表单的不同状态

在这里,您可以看到它的作用:


取消


拯救
这样,您还可以拥有更多的游乐场,例如:

<button type="submit" [disabled]="submitActive || cancelActive">...</button>
。。。
如果出于某种原因想执行此操作,您可以简单地禁用
submit
按钮,而不显示加载动画


此外,假设表单中有一个
元素。用户切换到该元素(通过单击或按tab键),完成编辑后按Enter键,在这种情况下,浏览器也会自动提交表单;因此,这将使您现有的代码结构更加复杂。

首先。。。为什么需要这样操作dom(添加加载),有什么特殊原因吗?save和cancel函数将异步调用web服务器。我想禁用按钮,并在处理异步调用时在按钮上显示旋转图标。我正在制作一个动态表单组件。可以有多个窗体,每个窗体上有多个按钮。因此,通过一个固定变量跟踪哪个按钮正在加载似乎比只向按钮的dom添加
加载
类效率要低。有些人只是在一个布尔标志就足够了的情况下才这么做,但我很好地理解了你在这种情况下的理由:)@Curtis我不确定你的效率问题是什么。关键是Angular通过将状态存储在组件而不是DOM中来实现这一点。代码更少,性能也不差。OP的方法有什么问题?在不了解问题的情况下建议解决方法是有问题的。而且,如果用户使用enter提交表单,这也不起作用。。。我知道,这里不是这样,但你应该始终妥善处理提交。我以前尝试过,我似乎记得Subm存在一些问题
save() {
    console.log(this.saveButton);
}
<button #saveButton *ngIf="hasSave">
  Save
</button>
<button #cancelButton *ngIf="hasCancel" (click)="clickEvent(cancelButton)">
  Cancel
</button>
export class FormFieldOverviewExample {
  cancelActive = false;
  submitActive = false;

  // this is for submit event
  saveEvent(event: Event) {
    // additional logic can be added
    // if(!this.cancelActive) return;

    this.submitActive = true;
    this.cancelActive = false;
  }

  // this is for cancel event
  cancelEvent(event: Event) {
    // additional logic can be added
    // if(!this.submitActive) return;

    this.submitActive = true;
    this.cancelActive = false;
  }

}
<button type="submit" [disabled]="submitActive || cancelActive">...</button>