form のエンターサブミットを防ぐには
- カテゴリ:
- JavaScript
- ブラウザ
- コメント数:
- Comments: 2
◆ form タグにまかせないでそのまま input などを並べて js で処理するほうがやっぱりいいと思った
◆ IE なんてゴミ箱に捨てれば良いんだ
◆ IE なんてゴミ箱に捨てれば良いんだ
あまり サーバサイドにデータ送るようなもの作らないし 作っても送る前に加工することが多いので 普段から form タグをつかうことはほとんどないのですが使ってみると以外に困るのがエンターでサブミットされる機能です
input ひとつとボタンひとつの作りなら良い機能なのですけど複数入力のときに途中でサブミットされたりすると困ります
サブミットする前に入力チェック (checkValidity) をするべきで してるなら未入力だとサブミットされないから大丈夫
という考えかたもありますが 未入力おっけいだったり エンター押しただけで「ここエラーです」がいっぱいでてくるのも邪魔です
よくある問題だしそろそろ form 自体に preventEnterSubmit とかプロパティができてもいいと思うのですがないようです
単純に form が onkeydown をチェックして Enter なら preventDefault と すると textarea で改行できなくなったり他のところに影響でます
タグの種類と type 属性をみて エンターでサブミットするかを調べて さらにそのイベント元が submit のボタンじゃないときは preventDefault というのはちょっと大変です
と思ったのですがやってみると onsubmit イベントは絶対 target が form でクリックしたボタンやエンターキーを押したなどの情報はとれないようでした
クリックしていないのに click イベントが起きるということはプロパティから本当のクリックかどうかを判断できるはず
と言う考えでやってみたのがこれ
関係ないのは弾くように type === "submit" は必須
クリックしてないときのクリックイベントは eve.x と eve.y が 0 になってるので これでエンターキーでのサブミットかの判断をします
最後に <input type="submit"> にフォーカスしてエンターしたときはサブミットしたいので アクティブな要素かもチェックします
アクティブな要素(フォーカス中)とクリック対象が違っていて 実際にはクリックしていないクリックイベントで イベントの対象が submit と言う状態をエンターキーのサブミットとみなしてイベントをキャンセルしています
これで簡単にエンターサブミットを防止できます
といいたいのですが IE11 にも対応する必要がある場合は使えません
なんでこんなぽんこつが2025年までサポートなんでしょうね
ですが 実際にクリックしていないクリックイベントで event.x と event.y が 0 になりません
-574 など負の数です
数値もウィンドウサイズでかわるようで固定ではありません
条件を === 0 から <= 0 にすればとりあえず解決できそう ではあります
本当に大丈夫か心配がありますけど
他に実際のクリックとの判断できそうなものに event.detail があります
これはクリックした数が入るので click イベントだと 1 ダブルクリックだと 2 クリックしてないと 0 になります
なのに IE11 は event.detail プロパティは一応存在するのにクリックしてもずっと 0 でした
あまりすっきりしないけど event.x と event.y が 0 以下なら……と諦めたところで screenX/Y が 0 になってるのを発見しました
これで完成
と思ったらまだありました
input をエンターしたときの click イベントで activeElement が input でなく button になっていました
css セレクタで :focus にしても同じで button になっています
これを対応するのは簡単には行かなそうなので IE 対応が必要なら最後の条件なしにして 代わりに type="submit" にフォーカスしてエンターすると submit メソッドを呼びます
これで今度こそ大丈夫なはずといいですが IE11 にはやっぱリ問題があって input をエンターで確定すると見た目はどこにもフォーカスしていないように見えるのに 内部的に button がフォーカスされています
onclick の時点で activeElement が button になっていましたが一時的にではなくてそのままフォーカスが移ってるようです
この状態でエンターすればやっぱりサブミットされるので 2 回エンターすればサブミットされることになります
サブミットボタンのエンターはなしでボタンクリックのみでいいかなー
とりあえず追加した onkeydown を消して これで完成としたかったのですが 別の問題に気付いてしまいました
ボタンにフォーカスあててスペースキーを押したときに発生する click イベントでは screenX/Y が 0 でなく 400 などの正の数字でした
もう IE なんて知らない
input ひとつとボタンひとつの作りなら良い機能なのですけど複数入力のときに途中でサブミットされたりすると困ります
サブミットする前に入力チェック (checkValidity) をするべきで してるなら未入力だとサブミットされないから大丈夫
という考えかたもありますが 未入力おっけいだったり エンター押しただけで「ここエラーです」がいっぱいでてくるのも邪魔です
よくある問題だしそろそろ form 自体に preventEnterSubmit とかプロパティができてもいいと思うのですがないようです
単純に form が onkeydown をチェックして Enter なら preventDefault と すると textarea で改行できなくなったり他のところに影響でます
タグの種類と type 属性をみて エンターでサブミットするかを調べて さらにそのイベント元が submit のボタンじゃないときは preventDefault というのはちょっと大変です
案1
onsubmit で event.target が submit タイプ以外なら preventDefault ならシンプルかもと思ったのですがやってみると onsubmit イベントは絶対 target が form でクリックしたボタンやエンターキーを押したなどの情報はとれないようでした
案2
試してると input のエンターによるサブミットは内部的に type="submit" のボタンがクリックされたことになるようで onclick イベントが発火していましたクリックしていないのに click イベントが起きるということはプロパティから本当のクリックかどうかを判断できるはず
と言う考えでやってみたのがこれ
var form = document.querySelector("form")
form.onclick = eve => {
if(eve.target.type === "submit"
&& eve.x === 0
&& eve.y === 0
&& document.activeElement !== eve.target){
eve.preventDefault()
}
}
form.onclick = eve => {
if(eve.target.type === "submit"
&& eve.x === 0
&& eve.y === 0
&& document.activeElement !== eve.target){
eve.preventDefault()
}
}
関係ないのは弾くように type === "submit" は必須
クリックしてないときのクリックイベントは eve.x と eve.y が 0 になってるので これでエンターキーでのサブミットかの判断をします
最後に <input type="submit"> にフォーカスしてエンターしたときはサブミットしたいので アクティブな要素かもチェックします
アクティブな要素(フォーカス中)とクリック対象が違っていて 実際にはクリックしていないクリックイベントで イベントの対象が submit と言う状態をエンターキーのサブミットとみなしてイベントをキャンセルしています
これで簡単にエンターサブミットを防止できます
といいたいのですが IE11 にも対応する必要がある場合は使えません
なんでこんなぽんこつが2025年までサポートなんでしょうね
IE では
IE でも submit ボタンが click されたことになりますですが 実際にクリックしていないクリックイベントで event.x と event.y が 0 になりません
-574 など負の数です
数値もウィンドウサイズでかわるようで固定ではありません
条件を === 0 から <= 0 にすればとりあえず解決できそう ではあります
本当に大丈夫か心配がありますけど
他に実際のクリックとの判断できそうなものに event.detail があります
これはクリックした数が入るので click イベントだと 1 ダブルクリックだと 2 クリックしてないと 0 になります
なのに IE11 は event.detail プロパティは一応存在するのにクリックしてもずっと 0 でした
あまりすっきりしないけど event.x と event.y が 0 以下なら……と諦めたところで screenX/Y が 0 になってるのを発見しました
var form = document.querySelector("form")
form.onclick = function(eve) {
if(eve.target.type === "submit"
&& eve.screenX === 0
&& eve.screenY === 0
&& document.activeElement !== eve.target){
eve.preventDefault()
}
}
form.onclick = function(eve) {
if(eve.target.type === "submit"
&& eve.screenX === 0
&& eve.screenY === 0
&& document.activeElement !== eve.target){
eve.preventDefault()
}
}
これで完成
と思ったらまだありました
input をエンターしたときの click イベントで activeElement が input でなく button になっていました
css セレクタで :focus にしても同じで button になっています
これを対応するのは簡単には行かなそうなので IE 対応が必要なら最後の条件なしにして 代わりに type="submit" にフォーカスしてエンターすると submit メソッドを呼びます
var form = document.querySelector("form")
form.onclick = function(eve) {
if(eve.target.type === "submit"
&& eve.screenX === 0
&& eve.screenY === 0){
eve.preventDefault()
}
}
form.onkeydown = function(eve) {
if(eve.keyCode === 13 && eve.target.type === "submit"){
eve.preventDefault()
this.submit()
}
}
form.onclick = function(eve) {
if(eve.target.type === "submit"
&& eve.screenX === 0
&& eve.screenY === 0){
eve.preventDefault()
}
}
form.onkeydown = function(eve) {
if(eve.keyCode === 13 && eve.target.type === "submit"){
eve.preventDefault()
this.submit()
}
}
これで今度こそ大丈夫なはずといいですが IE11 にはやっぱリ問題があって input をエンターで確定すると見た目はどこにもフォーカスしていないように見えるのに 内部的に button がフォーカスされています
onclick の時点で activeElement が button になっていましたが一時的にではなくてそのままフォーカスが移ってるようです
この状態でエンターすればやっぱりサブミットされるので 2 回エンターすればサブミットされることになります
サブミットボタンのエンターはなしでボタンクリックのみでいいかなー
とりあえず追加した onkeydown を消して これで完成としたかったのですが 別の問題に気付いてしまいました
ボタンにフォーカスあててスペースキーを押したときに発生する click イベントでは screenX/Y が 0 でなく 400 などの正の数字でした
もう IE なんて知らない
COMMENT
コメント一覧 (2)
-
- 2019/07/29 17:03
-
detaul?
>
なのに IE11 は event.detaul プロパティは一応存在するのにクリックしてもずっと 0 でした
-
- 2019/07/29 19:28
-
>>1
detail のタイプミスですね
指摘ありがとうございます
修正しました