繁体   English   中英

Angular如何在表单提交上获取按钮元素

[英]Angular how to get button element on form submit

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

HTML

<button #cancelButton class="button-with-icon" type="button" *ngIf="hasCancel" mat-raised-button color="warn" [disabled]="isLoading" (click)="clickEvent(cancelButton)">
    <mat-spinner *ngIf="isLoading" style="display: inline-block;" diameter="24"></mat-spinner>
    Cancel
</button>

TS

clickEvent(button: MatButton) {
    console.log(button);
}

在这种情况下,按钮元素将被传递,您可以访问它以向按钮添加加载类。

但是,如果您使用提交按钮尝试相同的操作,则会显示undefined

HTML

<form (ngSubmit)="save(saveButton)">
    <button #saveButton class="button-with-icon" type="submit" *ngIf="hasSave" mat-raised-button color="primary" [disabled]="isLoading">
        <mat-spinner *ngIf="isLoading" style="display: inline-block;" diameter="24"></mat-spinner>
        Save
    </button>
</form>

TS

save(button: MatButton) {
    console.log(button);
}

在这种情况下,按钮是undefined因为按钮上的*ngIf阻止它从表单的范围。 我可以删除*ngIf并隐藏按钮,但是这会留下DOM上的按钮,我不想这样做。

这是一个堆栈闪电战: https ://stackblitz.com/edit/angular-zh7jcw-mrqaok file = app%2Fform-field-overview-example.html

我已经尝试向保存按钮添加一个额外的单击事件以将按钮设置为加载但是单击事件会先触发并将按钮设置为禁用,然后才能阻止调用submit事件。

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

有什么建议么?

更新我现在了解您的特定问题。 问题是按钮上的*ngIf 这打破了参考。 将其更改为[hidden] ,它应该工作。 这是一个更新的StackBlitz: https ://stackblitz.com/edit/angular-zh7jcw-pcuuyv

至于为什么会这样,我认为这很好地描述了这个问题: https//stackoverflow.com/a/36651625/64279

原始答案:

我甚至都不会把它传入。只需在你的课程中添加:

 @ViewChild('saveButton') button;

然后你可以在你的保存方法中引用它:

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

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

tl; dr这是我的解决方案: https//stackblitz.com/edit/angular-zh7jcw-ythpdb


编辑:正如我刚才注意到的那样,@ AJT_82非常清楚地解释了OP对参考元素的原始问题。 所以我现在删除了我之前的答案。


但是我建议以下解决方案在关注点分离角度方式处理方面更合适,即通过引入两个新成员cancelActivesubmitActive ,您将能够更灵活地处理表单的不同状态。

在这里你可以看到它的实际效果: https//stackblitz.com/edit/angular-zh7jcw-ythpdb

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;
  }

}
<form (ngSubmit)="saveEvent($event)">
  <button  class="button-with-icon"  type="button"  *ngIf="hasCancel"  mat-raised-button color="warn"  [disabled]="cancelActive"  (click)="cancelEvent($event)">
    <mat-spinner *ngIf="cancelActive" class="spinner" diameter="15"></mat-spinner>
    Cancel
  </button>
  <br><br>
  <button class="button-with-icon" type="submit" *ngIf="hasSave" mat-raised-button color="primary" [disabled]="submitActive">
    <mat-spinner *ngIf="submitActive" class="spinner" diameter="15"></mat-spinner>
    Save
  </button>
</form>

这样你就可以有更多游乐场,例如:

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

你可以简单地禁用submit按钮而不显示它的加载动画,如果你想出于某种原因这样做...

此外,假设您的表单中有<input type="text" />元素。 用户切换到该元素(通过点击或标签按下),在完成编辑后按下Enter键,在这种情况下,表格也由浏览器自动提交; 所以这会使你现有的代码结构中的事情变得更加复杂。

而不是在窗体上使用ngSubmit事件处理程序使用保存按钮上的click事件处理程序。 将类型保留为submit以便在用户使用输入控件上的Enter键提交表单时它仍然有效。

<form #formElement="ngForm">
    ...
    <button #saveButton (click)="save(saveButton, formElement)" type="submit" ...>
        <mat-spinner ...></mat-spinner>
        Save
    </button>
</form>

您还可以通过使用对象跟踪哪个按钮处于加载状态来避免需要将loading类添加到DOM。 这里的工作示例。 这也允许您拥有许多按钮,而无需为每个按钮创建固定变量。

 class FormFieldOverviewExample { hasCancel = true; hasSave = true; isLoading = {}; saveEvent(event, buttonName, form) { console.log(buttonName); if(form.valid) { this.isLoading[buttonName]=true; // ... } else { this.isLoading[buttonName]=false; console.warn("Form not submitted because it contains errors"); } } clickEvent(event, buttonName) { console.log(buttonName); this.isLoading[buttonName]=true; // ... } } 
 form { display: none; } 
 <form #formElement="ngForm"> ... <button (click)="clickEvent($event, 'cancelButton')" [disabled]="isLoading['cancelButton']" *ngIf="hasCancel" type="button" ...> <mat-spinner *ngIf="isLoading['cancelButton']" ...></mat-spinner> Cancel </button> <br><br> <button (click)="saveEvent($event, 'saveButton', formElement)" [disabled]="isLoading['saveButton']" *ngIf="hasSave" type="submit" ...> <mat-spinner *ngIf="isLoading['saveButton']" ...></mat-spinner> Save </button> </form> 

这实际上与提交函数无关,但与角度和结构指令有关。 当你应用结构指令( ngForngIf ...)时, ngIf角度是创建一个ng-template节点。 这意味着,在结构指令范围内定义的模板引用变量在该节点中可用。

那你在这里有什么:

<button #saveButton *ngIf="hasSave">
  Save
</button>

表示saveButton模板引用仅在为该按钮创建的ng-template内可用,因此在提交函数中不可用。

我们在这里有什么:

<button #cancelButton *ngIf="hasCancel" (click)="clickEvent(cancelButton)">
  Cancel
</button>

是单击事件在按钮上,因此cancelButton模板引用变量可用于该事件。

使用hidden而不是像其他答案中建议的ngIf ,解决了这个问题,因为我们只是......好吧,隐藏元素。

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

loading: boolean = false;

在您的模板中,将此类绑定为

[class.loading]="loading"

在您的方法中,最初将此属性设置为true,然后在异步调用完成后将其设置为false。 类似使用相同的变量将disabled属性设置为

[disabled]="loading"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM