チェックボックスの DOM 要素の取得方法に注意
チェックボックスを取得する JavaScript の書き方が古いと、思わぬバグを引き起こすことがある。
例えば以下のような構成の HTML フォームがあったとして。
<form name="myForm" method="post" action="/Send">
<p>このページをどこで知りましたか?</p>
<ul>
<li><input type="checkbox" name="questionnaire" value="google"> Google 検索で</li>
<li><input type="checkbox" name="questionnaire" value="web"> 別の Web サイトからのリンクで</li>
<li><input type="checkbox" name="questionnaire" value="friend"> 友達に聞いた</li>
</ul>
<p><input type="submit" value="送信"></p>
</form>
「古い書き方」というのは、名前がよく分からないのだが、Form オブジェクトを捕まえて、name
属性値をドット記法で繋いで書いていくやり方。例えば name="questionnaire"
という名前のチェックボックスを取得するときに、以下のように書いたとする。
var checkboxes = document.myForm.questionnaire;
// チェックボックスのチェック状況を1つずつ見て何か処理をする
for(var i =0; i < checkboxes.length; i++) {
// (何か処理)
}
この書き方をしている場合、HTML によっては問題が起こり得る。
チェックボックスが1つしかない場合
例えば、ユーザによってはチェックボックスが1つしか表示されないような場合があったとする。
<form name="myForm" method="post" action="/Send">
<p>このページをどこで知りましたか?</p>
<ul>
<li><input type="checkbox" name="questionnaire" value="google"> Google 検索で</li>
</ul>
<p><input type="submit" value="送信"></p>
</form>
このような HTML に対し、先ほどの JavaScript を発動させると、スクリプトエラーになる。
var checkboxes = document.myForm.questionnaire;
// チェックボックスのチェック状況を1つずつ見て何か処理をする
for(var i =0; i < checkboxes.length; i++) { /* ← この行でスクリプトエラーになる */
// (何か処理)
}
なぜかというと、この記法で要素を取得したとき、対象の要素が1つだと、配列ではなく1つの DOM オブジェクトとして取得されるため、checkboxes.length
というプロパティが存在しなくなってしまうのだ。
だから、この記法で対象の要素が1つの時にも正しく動作させるには、以下のようにプロパティの存在をチェックしないといけないのだ。
var checkboxes = document.myForm.questionnaire;
// チェックボックスのチェック状況を1つずつ見て何か処理をする
if(checkboxes.length) {
for(var i =0; i < checkboxes.length; i++) {
// (何か処理)
}
}
else {
// (要素が1つのみの時の処理)
}
そもそもこの記法を止めれば良い
上のような、name 属性名をドット記法で記述する書き方を何と呼ぶのか知らないが、この書き方は古い書き方のような気がする (最近見ないし)。
こうではなく、ちゃんと getElementsByName()
を使ってやれば、要素が1つでも必ず配列で取得できるので、余計な考慮が要らなくなる。
なお、getElementById()
を使うには、name 属性ではなく id 属性を振っておかないといけないので、form 要素には id 属性を付けておく。
<!-- id 属性を付与 -->
<form id="myForm" name="myForm" method="post" action="/Send">
<p>このページをどこで知りましたか?</p>
<ul>
<li><input type="checkbox" name="questionnaire" value="google"> Google 検索で</li>
</ul>
<p><input type="submit" value="送信"></p>
</form>
チェックボックスの方は id 属性を付けて個別に管理する必要はなく、getElementsByName()
で取得してやれば良い。
// こうすれば必ず配列で取れる
var checkboxes = document.getElementById("myForm").getElementsByName("questionnaire");
// チェックボックスのチェック状況を1つずつ見て何か処理をする
for(var i =0; i < checkboxes.length; i++) {
// (何か処理)
}