それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

HTMLのリセット(reset)ボタンで検索条件をクリアのときに、すでにデータがあるとクリアされない

html で検索フォーム

HTMLのFormで検索フォームを作ると、検索条件のリセットが欲しくなる。

とくにテストしているとリセットボタンが欲しくなる。

フォームのリセット

フォームのリセット、とても簡単です。HTMLの遺物を使えばいいんです。

<form action=search method=get>
<input type=search name=user value='' >
<input type=submit value=search>
<input type=reset value=reset >
</form>

とても簡単です、ボタンを一つおけばいいのですから

<input type=reset value=reset >

問題点:リセットはクリアじゃない

WEB側のCGI*1でHTMLを生成するとき

サーバー側でHTMLレンダリングを行っていると

<input type=search name=user value='takuya' >

サーバー側から送られた状態にリセットされます。

リセットボタンは、ユーザーの入力による変更を破棄であり、フォームのクリアではない。

解決策1

input[type=search] を使えばいい。検索フォームに input[type=text] は使わない

なぜか?input[type=search] はMDNに記載があるように、ブラウザ側でフォームの値を持ち回してくれる。なんちうHTML要素だ。

phpなどでecho が不要になるのである。

search なら次は書く必要がない。

よく見る、検索文字列のHTML代入だけど、これが不要。

<input type=search name=user value='<?php echo $cond;?>' >

type=search ならこれだけ

ブラウザが勝手にやります。

<input type=search name=user  >

これを使っておけば、input[value]は常に空っぽの状態になる。そのためリセットボタンは正しく動作する。

できる限りsearch を使っておく

できる限りsearchを使っておくと、リセットボタンが正しく動作する(HTMLにデフォルト値を入れないため)ということなので、type=searchがうまく使えるようにdisplay:noneと組み合わせて組み立ててあげればいい。ただし、ブラウザ次第で戻るボタンで値が戻る場合があり、ブラウザごとの挙動を調べ上げるのがちょっと不便。

解決策2

古のオーパーツ(FormElements)のAPIを使う。

ボタンにセレクトやチェックボックスが混じってるとDOM操作でフォームのインプットの各要素のValueを設定しておくのは面倒すぎる。

そこで、太古の昔に存在したFormElementsを使う。

var myForm = document.getElementById("#btn").form
myForm.elements[0].value='';
myForm.elements[1].value='';

ちょっとだけ、最近のJSぽく書いて、クリアボタンを設定する。

document.addEventListener("DOMContentLoaded", () => {
    document.getElementById("form_clear_btn").addEventListener('click', ev=>{
      const form = ev.target.form;
      Array.from(form.elements).forEach( e => e.value='' )
    });
})

MDN にドキュメントが残されていて、HTMLFormElement.elements の使い方が見れる。DOMにアクセスして値を書き換えるのだが、アクセス方法はHTMLFormElementsであり、HTMLFormElementを介してアクセスする。

JSのこの仕様を久しぶりに使ったんだぜ。この form.elements 関連のAPIって未完成だけど、React/Angularのように、フォームとDOMの分離を企図したような残滓(?)を感じる。

方法3

リセットボタンで、フォームの書き換えは諦めて、GETのquery_string ( ?name=value)を除去し、ブラウザを移動させてしまえばいい。

location.href=location.href.split('?')[0]

何も検索条件が入力されてない状態のURLを読み込めば、リセットボタンと同じ効果が得られるのである。実にシンプルな解決方法である。

リセットボタンの扱い

リセットボタンは、デフォルト値にリセットするわけです。

デフォルト値は<input value=123456 >のようにHTMLに仕込まれた値です。

リセットが効かない。フォームにリセットは無用ではありません。使いどころが大事なのである。

問い合わせフォームにクリアボタンを置くのは、たしかし無用の長物です。でも。検索フォームは違う。

「リセットボタンは検索時に使う」のです。データを検索しフィルタリングするときこそ、リセットボタンが役に立つのです。

リセットボタンは設置したたらだめ。と古い記事を見かけますが、それは”問い合わせフォーム”などPOSTするフォームの話であり、検索条件を入力するGETのフォームの話ではありません。「リセットボタンはだめ」と覚えていたなら、それは大きな間違いです。

といっても、問い合わせフォームで値をvalue=aaa で戻したときは不便です。

このようなめんどくさいところをさくっとJSON取得で解決できるので、ReactやAngularやVueが便利だと思うんだけどね。それら使ってないサイト・プロジェクトに、検索条件の維持とリセットのためだけにVueを埋め込むのもありえないよね。

ということで、検索系のHTMLをサーバーサイドレンダリングで十分なパフォーマンスが得られると考える場合、Vue・ReactでSPAする意味もあまりない気がするんですよねぇ。*2

参考資料

*1:あえてこういう古い言いまわしをている

*2:検索結果のHTML生成がキャッシュされ、多人数がリバプロ経由で再配信を受けとれる場合ね