CodeSandboxを使ってToDoアプリを作成中なのだが、その続き。
前回までで、概ね動くものはできたのだが、ちょっと問題点っぽい動作があったので、今回はそこを直してみる。
過去記事:
テキストボックスにカーソルがある状態でEnterキーを押すとページがリロードされる
これが問題点。
今回のToDoアプリの仕様は、テキストボックスに文字列を入力して、「やること追加」ボタンを押すと、やることリストに文字列が表示されるというモノ。
テキストボックスに文字列が入っていない状態で、「やること追加」ボタンを押した場合は、エラーメッセージが出てやることリストには追加できないようにする仕様。
ここで、あまり考えていなかったのが、テキストボックスにカーソルがある状態でEnterキーを押すという操作。
基本、ソフトって書いたようにしか動かない、というイメージがあったので、処理書いてないんだから、当然何も起こらないでしょ、と思っていたわけです。最初は。
でも、なぜか、何も処理を書いていないはずなのに、Enterキーでページがリロードする。
これ如何に?
デフォルトの動作とは?
HTMLにはデフォルトの動作というモノがあるらしい。
リンクをクリックすればリンク先に飛んだり、フォームのSubmitボタンを押せば送信される。チェックボックスをクリックすると、チェックボックスがON/OFFするのが、ブラウザで設定されているデフォルトの動作になる。
これは、HTML内で簡単に処理させるための仕組みだと思うけど、複雑なことをJavaScriptでやらせようと思ったら、もともとあるデフォルトの動作が邪魔になることがある。
そういう時に、このデフォルトの動作を止めることができる。
とはいっても、どんなイベントでも止められるわけではなくて、そのイベントのcancelableというプロパティがtrueのイベントだったら、デフォルト動作を止めることができる。
ていうか、これって、そもそもデフォルト動作っていうのがどういうモノかっていうのをわかっていないと、止めようがないんじゃないかと思うんだけど。
まあ、今回みたいに、何かあるたびに、一つずつ解決していくしかないのかな。
今回のToDoアプリにおけるデフォルト動作
今回ToDoアプリを作っていて、困ったな、と思ったのが、冒頭の「テキストボックスにカーソルがある状態でEnterキーを押すと、ページがリロードされる」ということ。
イロイロ調べてみると、
入力欄が1つだけのフォームは、EnterキーでSubmitされる
らしいということが判明。(マジかw)
HTMLの仕様らしい。
- 入力欄が1つだと、document.documentURI へSubmitする
- 入力欄が2つ以上あると、勝手にSubmitされない
document.documentURIは、自分自身のURIだから、ページがリロードされているっていう現象は納得できる。(そんな仕様は納得できないけどww)
意図しない動きを回避するには?
今回の例で行くと、テキストボックスでEnterキー押しても何も起こらないようにしたい!ということになる。
方法としては、HTML側で回避する方法と、JavaScript側で回避する方法がある。
HTML側で回避する方法
HTML側で回避するなら、form要素のonsubmit属性に「return false」を設定する。
HTML
<form class="task_form" onsubmit="return false;"> <input class="task_input" type="text" /> <button class="task_submit" type="button">やること追加</button> </form>
onsubmitは、任意のJavaScript関数を実行することができるようになっている。
ここに関数を記述すると、フォームをSubmitする前に、そのJavaScriptの関数が実行される。(例えば、フォームの内容をチェックする関数なんかを入れておけば、送信前にチェックできる。)
逆に、form要素に対してデフォルトの処理を何もさせたくないのであれば、このonsubmitをreturn falseにしておけばよい。
そのほかの方法としては、フォームの中に入力欄が2つ以上あれば、勝手にSubmitされないので、ダミーの入力欄を作っておくというのも、1つの方法かもしれないが、コード的にそれはどうなんだろうか・・・。(使わないのにダミーとして置いておくっていうのも・・・。)
JavaScript側で回避する方法
JavaScript側で回避するなら、event.preventDefault()を使う。
ちなみに、上のonsubmitにも、event.preventDefault()を設定してデフォルト動作を止めることも可能だが、今回の場合は、Enterキーが押された時だけに適用したいので、この方法はHTMLだけでは回避できない。
HTML
<form class="task_form"> <input class="task_input" type="text" /> <button class="task_submit" type="button">やること追加</button> </form>
JavaScript
const taskForm = document.getElementsByClassName('task_form')[0]; taskForm.addEventListener('keypress', (evt) => { if (evt.keyCode === 13) { evt.preventDefault(); } });
これで、Enterキーを押された時だけ、デフォルト動作を回避できる。
今回のToDoアプリでは、シンプルに実装できるHTMLのonsubmitをreturn false方法をで返す方法を選択する。
コードを書いていないのに、ブラウザ側が勝手によしなにしてくれる、というのは何とも余計なお世話というか、なんというか・・・。
こういう言語の特徴みたいなものを、うまく使いこなしていくことが大事なんだなと、つくづく思う。
言語の文化、奥深い。