ボタン連打防止の実装方法について

現在、下記のように実装しているのですが、
ボタン押下直後ではなく、確定処理メソッド(submit())が終了するタイミングでしか
ボタンが非活性になりません。

押下直後に非活性化するには、どのように実装すればよいのでしょうか?

■.html

  <button type="button" (click)="submit()" [disabled]="submitFlag">確定</button>

■.ts

public submitFlag: boolean = false;

submit(): void {
    this.submitFlag= true;
      :
 (確定処理)
   : 
}

確定処理が重たいのが原因のようですので、

submit() {
  this.submitFlag = true;
  setTimeout(() => {
    // 確定処理
  });
}

のように逃すのはどうでしょう?

ご返信ありがとうございます。
挙動としては思い通りになりました。

ただ、こちらの勉強不足で大変申し訳無いのですが、
なぜsetTimeoutで囲むとsubmitFlagの変更が反映されるのかが理解できず。。
ご教示いただけますと幸いです。

内部の動作にあまり詳しくないのですが、値の変更を検出するChange Detectionの仕組みがあり、メソッドの呼び出しが完了したタイミングでChange Detectionが行われるようです。

メソッドの呼び出し完了以外にも Change Detectionが行われるタイミングがあり、その1つに setTimeoutの呼び出しがあるようです。

  • all browser events (click, mouseover, keyup, etc.)
  • setTimeout() and setInterval()
  • Ajax requests

と、↓の記事をざっと見てみただけなので、間違っていたら詳しい方ご指摘お願いします。

ご返信ありがとうございます。
ChangeDetectorについて調査し、
ChangeDetectorRefを使用して非活性化処理の直後で強制描画を走らせるようにしました。

import { ChangeDetectorRef } from '@angular/core';

constructor(private changeDetectorRef: ChangeDetectorRef) { }

public submitFlag: boolean = false;

submit(): void {
    // 非活性フラグON
    this.submitFlag= true;
    // 強制描画
    this.changeDetectorRef.detectChanges();
   :
(確定処理)
   : 
}

描画タイミングをずらしたいケースはよくありますが、タイムアウトよりrequestAnimationFrameを使った方がいいです。

1 Like

そうですね、 pukuさんのアイデア(setTimeout)が一番シンプルで良いかと思います。(rAFもZone.js的にはほとんど差はないです)

逆に、明示的に this.changeDetectorRef.detectChanges(); を呼び出すことは割り込んでの処理になるためパフォーマンスの劣化を招きかねません。

setTimeoutで変更検知が直ちに行われるのは、setTimeoutに渡す関数の実行はZone.jsの中でタスクキューに積まれ、イベントハンドラであるsubmit()メソッドの実行タスクが完了したあとに処理されるからです。
詳しく知りたければZone.jsについて調べてみてください

1 Like