我的页面上有多种形式。每个表单上都有许多按钮。我想在按钮按下后实现加载微调器。当我使用常规点击事件时,我可以传递按钮:
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);
}
在这种情况下,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事件,但是看不到任何链接到所单击按钮的内容。
有什么建议吗?
答案 0 :(得分:3)
更新,我现在了解您的特定问题。问题是按钮上的*ngIf
。它打破了参考。将其更改为[hidden]
,它应该可以工作。这是更新的StackBlitz:https://stackblitz.com/edit/angular-zh7jcw-pcuuyv
关于发生这种情况的原因,我认为这可以很好地描述问题:https://stackoverflow.com/a/36651625/64279
原始答案:
我什至都不会传递它。只需在您的班级中添加它即可:
@ViewChild('saveButton') button;
然后您可以在保存方法中引用它:
save() {
console.log(this.saveButton);
}
但是我还要补充一点,从插值调用函数不是一个好主意,因为它可能会导致性能问题。相反,您应该订阅一个设置属性的事件,然后在视图中引用该属性。这样,仅在事件触发时才调用该函数,而不是页面的每次呈现。
答案 1 :(得分:3)
tl; dr 这是我的解决方案:https://stackblitz.com/edit/angular-zh7jcw-ythpdb
编辑:正如我刚刚注意到的那样,@ AJT_82很好地解释了OP的原始问题,其中引用元素非常好。因此,我现在删除了先前的答案。
但是,我建议以下解决方案在关注点分离和以有角度的方式做事方面更合适,即引入两个新成员{ {1}}和cancelActive
,您将能够更灵活地处理表单的不同状态。
在这里您可以看到它的运行情况:https://stackblitz.com/edit/angular-zh7jcw-ythpdb
submitActive
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
元素。用户切换到该元素(通过单击或按下Tab键),并在完成编辑后按Enter键,在这种情况下,浏览器也会自动提交表单;因此这会使现有代码结构中的事情变得更加复杂。
答案 2 :(得分:2)
在表单上使用ngSubmit
事件处理程序,而不是在表单上使用click
事件处理程序。将类型保留为submit
,以便当用户在输入控件上使用Enter
键提交表单时,该类型仍然有效。
<form #formElement="ngForm">
...
<button #saveButton (click)="save(saveButton, formElement)" type="submit" ...>
<mat-spinner ...></mat-spinner>
Save
</button>
</form>
通过使用一个对象来跟踪哪个按钮处于加载状态,您还可以避免将loading
类添加到DOM。工作示例here。这也使您可以拥有许多按钮,而不必为每个按钮创建一个固定变量。
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>
答案 3 :(得分:2)
这实际上与Submit函数无关,而与angular和structure指令有关。当您应用结构指令(ngFor
,ngIf
...)时,幕后的作用是创建一个ng-template
节点。这意味着,在该节点中仅可以使用在结构指令的范围内定义的模板引用变量。
那么您在这里拥有什么
<button #saveButton *ngIf="hasSave">
Save
</button>
意味着saveButton
模板引用仅在为按钮创建的ng-template
内部可用,因此在提交功能中不可用。
我们在这里拥有什么
<button #cancelButton *ngIf="hasCancel" (click)="clickEvent(cancelButton)">
Cancel
</button>
是单击事件在按钮上,因此cancelButton
模板引用变量可用于该事件。
使用hidden
代替其他答案中建议的ngIf
,可以解决此问题,因为我们只是隐藏元素。
答案 4 :(得分:1)
针对您的情况,您不应将元素传递给函数,然后在其上操作类,而只需维护一个变量以加载状态。在您的组件中,将其初始化为
loading: boolean = false;
然后在您的模板中,将此类绑定为
[class.loading]="loading"
在您的方法中,首先将该属性设置为true,然后在异步调用完成后将其设置为false。类似地,使用相同的变量将禁用属性设置为
[disabled]="loading"