如何处理Angular2

时间:2016-05-09 16:43:45

标签: 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;
    }
  }

我这样做是对吗还是有更优质/优雅的方式来做这件事?

6 个答案:

答案 0 :(得分:7)

处理双重提交很容易错误。在包含<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无法知道submit()中的API调用何时或是否失败或成功。即使Angular提供的属性意味着“只需单击提交按钮并且它也通过了所有验证”,您可以挂起[disabled] =“thatProperty”,Angular将不知道何时设置属性返回,例如当您的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;
}

如果您的API调用有多个共享一个常见错误处理程序的路径,那么您还需要将HTMLButtonElement传递给它们,因为它们无法再使用{{1}将其从组件中删除}。

(或者,不是声明和传递#submitBtn,而是已经声明了#theForm,所以将其传递为:NgForm,组件代码可以向下钻取到按钮...或覆盖整个表单或者其他什么。)

这个解决方案是否优于声明另一个与this.disableButton略有不同的布尔值的优雅意见,但事实上Angular无法知道组件的submit()及其所有异步进程何时是完成没有订阅。

答案 1 :(得分:5)

这也应该有效:

<button #button (ngSubmit)="button.disabled = true" type="submit">Submit<button>

或仅(click)代替(ngSubmit)

更新(请参阅评论)

<button #button [disabled]="!form.valid || button.hasAttribute('is-disabled')"
     (ngSubmit)="button.setAttribute('is-disabled', 'true')"
     type="submit">Submit<button>

更新(使用指令)

@Directive({
  selector: 'button[type=submit]'
})
class PreventDoubleSubmit {

  @HostBinding() disabled:boolean = false;

  @Input() valid:boolean = true;      

  @HostListener('click') 
  onClick() {
    if(!valid) {
      return;
    }
    this.disabled = true;
  }
}

并像

一样使用它
<button type="submit" [valid]="!form.valid">Submit<button>

您需要将其添加到要使用它的组件的directives: [PreventDoubleSubmit],或者全局提供

provide(PLATFORM_DIRECTIVES, {useValue: [PreventDoubleSubmit], multi: true})

答案 2 :(得分:3)

由于您在提交通话中已经在进行disableButton = true,因此您可以在调用提交方法之前检查disableButton

<强>模板

<form (submit)="!disableButton && submit()" >
    <--! Some Inputs -->
    <button [disabled]="disableButton" type="submit">Submit<button>
</form>

答案 3 :(得分:3)

我有一个稍微不同的方式(也许更简单)处理这个 - 虽然适用相同的原则。

基本上我要做的是:

  • 在组件上创建名为disableButton的变量,初始值为false
  • 然后,当单击该按钮时,将此变量设置为true
  • 然后在提交表单后重置为false。

这是我的html模板代码:

<form #form="ngForm" (ngSubmit)="handleSubmit(form.value, form.valid)">
   <button type="submit" [disabled]="form.invalid || disableButton">
      Submit
   </button>
</form>

这是我的班级:

export class UpdateForm {
   disableButton: boolean;
   constructor() { this.disableButton = false; }
   handleSubmit(formData: any, isValid: boolean) {
      if (isValid) {
         this.disableButton = true; // the button will then be disabled
         onHandleUpdate(formData);
      }
   }
   onHandleUpdate(formData) {
      this.disableButton = false; // the button will renable
   }
}

答案 4 :(得分:0)

您可能有一个基本组件公开了一个get,它告诉该组件是否忙。可以在模板上使用此get来禁用或启用按钮。对于执行异步调用的操作,基本组件具有受保护的方法,该方法接受函数调用。例如

基本组件

export abstract class BusyComponent {
    private _isBusy = false;

    get isBusy(): boolean {
        return this._isBusy;
    }

    protected async performBusyTask<T>(busyFunction: () => Promise<T>) {
        this._isBusy = true;
        try {
            return await busyFunction();
        } finally {
            this._isBusy = false;
        }
    }
}

子组件

class BusyComponentChild extends BusyComponent {

    constructor(private dependency: Dependency) {
        super();
    }

    doSomethingAsync(): Promise<number> {
        return this.performBusyTask<number>(() => this.dependency.doSomethingAsync());
    }
}

模板

<button type="submit" [disabled]="isBusy || !form.valid">Save</button>

答案 5 :(得分:0)

如果面临双重提交,请检查模板中是否没有两次调用Submit方法。例如,它可能在您的<form>以及提交的<button>标签中:

<form [formGroup]="form" (ngSubmit)="onSubmit()">

    // very long form content

    <button type="submit" (click)="onSubmit()">Submit</button>

</form>