如何在Angular2中处理双重提交

Das*_*kus 19 angular

如果我快速点击我的提交按钮,表单会被提交两次或更多次.我的想法是使用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)

我这样做是对吗还是有更优质/优雅的方式来做到这一点?

Ron*_*omb 9

处理双重提交很容易做错.在表格上<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()及其所有异步进程何时在没有订阅的情况下完成.


Gün*_*uer 5

这也应该有效:

<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)

  • 是的,这不是最美的解决方案.我只是试图演示在组件类中不需要变量的方法.也许我误解了你的问题.您还可以创建实现该功能的指令.我会用这种方法更新我的答案. (2认同)