リクエストの二重送信防止に UIEvent.detail を利用する

更新系のボタンクリックでローディングを表示して二重クリックを防止する実装をよく見かけるが、次のような操作をするとリクエストが二重送信できることがある。

  1. ボタンクリック (ローディング表示)
  2. キーボードの Enter or Space 押下

ボタンクリックでボタンにフォーカスが当たるが、ローディングを表示してもボタンのフォーカスは外れない。なので、キーボードの Enter や Space 押下でボタンの click イベントが走ってリクエストが二重送信される。

たぶん、ボタンを disabled にするのが簡単かもしれないが、以降は UIEvent.detail プロパティを使って回避する方法。

developer.mozilla.org

サンプルコード

サンプルコードでは、ボタンクリックで overlay が表示されてボタンが二重クリックできなくなるが、キーボードの Enter や Space を押下するとコンソールに submit! が何度も表示される。

これに対して、ボタンの click イベントでキャンセルイベントを呼び出すようにすると事象が発生しなくなる。(L49 のコメントアウトを外す)

window.addEventListener('click', cancelKeyEvent, true)

event.detail プロパティには現在のクリック数 (> 0) が設定される。一方、キーボードの Enter や Space 押下のときは値は常に 0 になる。あとは、stopPropagation() でイベントをキャンセルする。

ちなみに event.pointerType === 'mouse'IE 用の判定。

現場からは以上です。