如果我快速点击我的提交按钮,表单会被提交两次或更多次.我的想法是使用disabled属性来防止这种情况,但我需要disableButon在每种形式中使用变量:
@Component({
selector: 'example',
template: `
<form (submit)="submit()" >
<--! Some Inputs -->
<button [disabled]="disableButton" type="submit">Submit<button>
</form>
`
})
export class ExampleComponent {
private disableButton: boolean = false;
.......
submit(){
this.disableButton = true;
/*
* API call
*/
this.disableButton = false;
}
}
Run Code Online (Sandbox Code Playgroud)
我这样做是对吗还是有更优质/优雅的方式来做到这一点?
处理双重提交很容易做错.在表格上<form #theForm="ngForm" (ngSubmit)="submit()">:
<button type="submit" [disabled]="theForm.submitted" />只有在没有任何验证的情况下才会起作用.按下按钮时,Angular的ngForm.submitted设置为true,而不是在表单通过验证后设置为true.(NgForm的"提交"属性实际上意味着"试图提交".)
<button type="submit" [disabled]="theForm.submitted && theForm.valid" /> 并不是更好:在提交验证错误后,当用户修复验证错误时,提交按钮会自动禁用,因为它们会重新提交.
ngForm.submitted直接或通过ngForm.resetForm()组件内部重置submit()是一个不好的选择,因为submitted您的主要变量控制是否以及在何处显示验证错误消息.
真正的问题:Angular无法知道您的API调用何时或是否submit()失败或成功.即使角度提供这意味着一个属性"刚刚点击提交按钮,它也通过了所有的验证"上,您可以挂[禁用] ="thatProperty",角也不会知道什么时候该属性设置回,比如当你的API呼叫错误,你想让用户再次按提交重新尝试服务器.
也许Angular可能会禁止所有提交函数的形式() => Observable<boolean>,它可以订阅你的提交的成功或失败,但是在框架中重置一个布尔值似乎有点过分.
因此,您必须在所有API调用完成后执行操作,并以某种方式通知Angular提交按钮已准备好重用.该操作要么是设置您正在执行的显式布尔值,要么是强制禁用.
这是如何在没有布尔值的情况下强制执行.
将#submitBtn之类的模板引用变量添加到提交按钮:
<button type="submit" #submitBtn class="green">Go!</button>
将它传递给您的组件submit():
<form (ngSubmit)="submit(submitBtn)" ...>
接受并使用它的组件方:
submit(submitBtn: HTMLButtonElement): void {
submitBtn.disabled = true;
/// API calls
submitBtn.disabled = false;
}
Run Code Online (Sandbox Code Playgroud)
如果你的API调用有多个共享一个常见错误处理程序的路径,那么你也需要将HTMLButtonElement传递给它们,因为它们不能再将它从组件中取出this.disableButton.
(或者,不是声明和传递#submitBtn,而是已经声明了#theForm,因此将其传递为:NgForm,组件代码可以向下钻取到按钮...或覆盖整个表单,或者其他.)
这个解决方案是否优于声明另一个与ngForm.submitted意见略有不同的布尔值,但事实上Angular无法知道组件的submit()及其所有异步进程何时在没有订阅的情况下完成.
这也应该有效:
<button #button (ngSubmit)="button.disabled = true" type="submit">Submit<button>
Run Code Online (Sandbox Code Playgroud)
或者只是(click)代替(ngSubmit)
更新(见评论)
<button #button [disabled]="!form.valid || button.hasAttribute('is-disabled')"
(ngSubmit)="button.setAttribute('is-disabled', 'true')"
type="submit">Submit<button>
Run Code Online (Sandbox Code Playgroud)
更新(使用指令)
@Directive({
selector: 'button[type=submit]'
})
class PreventDoubleSubmit {
@HostBinding() disabled:boolean = false;
@Input() valid:boolean = true;
@HostListener('click')
onClick() {
if(!valid) {
return;
}
this.disabled = true;
}
}
Run Code Online (Sandbox Code Playgroud)
并使用它
<button type="submit" [valid]="!form.valid">Submit<button>
Run Code Online (Sandbox Code Playgroud)
您需要将其添加到directives: [PreventDoubleSubmit]要使用它的组件中,或者全局提供它
provide(PLATFORM_DIRECTIVES, {useValue: [PreventDoubleSubmit], multi: true})
Run Code Online (Sandbox Code Playgroud)