一回しか押していないのに、申し込みが二件届いた。原因は僕のボタンだった
反応がないボタンは、もう一度押される。
押せなくするだけでは足りなかった、二重送信の話。
お問い合わせフォームから、同じ内容の申し込みが二件届いていた。
名前も本文も一字一句同じで、受け取った時刻だけが三秒違う。
いたずらでも手違いでもなかった。
送ってくれた人は、一回しか押していないつもりだった。
反応がないと、人はもう一度押す
送信ボタンを押してから、実際に受け付けが終わるまでには少し時間がかかる。
内容を保存して、通知のメールを送って、完了の画面を出す。
速い回線でも一秒、混んでいれば数秒。
その数秒のあいだ、画面には何も起きない。
ボタンは押す前とまったく同じ顔をして、そこに座っている。
押した人からすれば、これは「押せていない」のと区別がつかない。
だからもう一度押す。
僕だって、他人のサイトで同じことをしている。
つまり二重送信は、押した人の不注意ではない。
待たせているあいだ、こちらが何も言わなかったせいだった。
JavaScriptができるのは、押せなくすること
いちばん手っ取り早い対策は、押された瞬間にボタンを無効にすることだ。
JavaScript でボタンの disabled を true にすると、それ以降のクリックは効かなくなる。
ただ、ここに初心者がよく踏む段差がある。
送信ボタン自体を無効にするタイミングを間違えると、送信そのものが止まってしまうことがある。
ブラウザは、無効になっている入力欄やボタンの値をサーバーへ送らない。
送信の処理が始まる前に無効にしてしまうと、そのボタンの値が抜け落ちる。
ボタンの値で処理を分けている作りだと、これで動かなくなる。
順番としては、送信の処理を先に走らせて、そのあとで無効にする。
フォームの送信イベントの中で無効化する、と覚えておけばだいたい間違えない。
それでも、JavaScript だけでは守りきれない
ここで終わりにしたいところだけれど、これだけでは足りない。
JavaScript は、見ている人の手元のブラウザで動いている。
何かの理由で読み込まれなければ、無効化のしかけごと存在しないことになる。
開発者向けの画面から、無効を解除して押すこともできる。
もっと素朴な経路もある。
送信は届いていたのに、返事が返る前に回線が切れた。
画面には何も出ないから、押した人は最初からやり直す。
このとき、ボタンの無効化はまったく仕事をしていない。
だから受け取る側でも守る。
フォームを表示するときに、その一回ぶんだけ有効な合言葉を紛れ込ませておく。
受け取ったらその合言葉を使い済みにして、同じものが二度目に来たら受け付けない。
もっと簡単に済ませるなら、同じ相手から同じ内容が短い時間のうちに来たら一件として扱う、という線引きでもいい。
完璧ではないけれど、実際に困っていた二重送信はこれでほとんど消えた。
いちばん効いたのは、押したことが見えるようにしたこと
しかけを二つ入れておいて、最後に効いたのは表示のほうだった。
押された瞬間に、ボタンの文字を「送信中」に変える。
色を薄くして、指のかたちのカーソルもやめる。
これだけで、二度押しの報告は目に見えて減った。
技術で止めるのは、起きてしまったことへの後始末だと思う。
起きなくするのは、待っている人に「いま動いています」と伝えることだった。
ボタンを直したというより、黙っていたのをやめただけの話だった。