SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

データが1件の時だけ、JavaScriptの必須チェックが誤動作する

WEBアプリでよくあるバグ

  • X ポスト
  • このエントリーをはてなブックマークに追加

原因

 JavaScript上でフォーム部品は、同名の要素が複数あるときのみ配列として扱われます。従って、今回のバグのようにチェックボックスが1個の時は、配列の長さを表すlengthプロパティが未定義(undefined)となり、for文の中に制御が移りません。

for (var i=0; i<sentakuChk.length; i++) {

 結果、表示データが1件のみの時は選択状態にかかわらず、エラーメッセージが表示されてしまいます。

対策

 動的に数が変わる同名のフォーム部品をJavaScriptで扱うときは、数が1個の時と複数の時で分けて処理を書きます。

プログラム修正例

 チェックボックスが1個か複数かは、JavaScriptでのチェックボックスを表すプロパティが配列になっているかどうか(=lengthプロパティがあるかどうか)で判断できます。

チェックボックス1個の場合に対応したソース
function check() {
  var sentakuChk = document.form1.sentakuChk;
  // チェックボックスが複数の時
  if (sentakuChk.length) {
    for (var i=0; i<sentakuChk.length; i++) {
      if (sentakuChk[i].checked) {
        return true;
      }
    }
  // チェックボックスが1個の時
  } else if (sentakuChk.checked) {
    return true;
  }
  alert("1件も選択されていません。");
  return false;
}
補足
 if文の条件に未定義(undefined)のプロパティが渡された場合、真偽値としては「偽」になるため、if文の中は実行されません。

プログラム修正例「0個対応」

 上記のコードは、チェックボックスが0個の場合には対応していません。0個の場合はdocument.form1.sentakuChk自体が未定義になるので、lengthプロパティの呼び出しでエラーが発生します。

チェックボックスがない時のエラー(IEの場合、ステータスバーの警告アイコンをダブルクリックすると表示されます)
チェックボックスがない時のエラー(IEの場合、ステータスバーの警告アイコンをダブルクリックすると表示されます)

 データが0件でも承認ボタンを表示する画面仕様ならば対応する必要があります。lengthプロパティを参照する前に、sentakuChkオブジェクトの存在確認が必要です。

チェックボックス0個の場合にも対応したソース
function check() {
  var sentakuChk = document.form1.sentakuChk;
  // チェックボックスが複数の時
  if (sentakuChk && sentakuChk.length) {
    for (var i=0; i<sentakuChk.length; i++) {
      if (sentakuChk[i].checked) {
        return true;
      }
    }
  // チェックボックスが1個の時
  } else if (sentakuChk && sentakuChk.checked) {
    return true;
  }
  alert("1件も選択されていません。");
  return false;
}
補足
 &&演算子は、左項が偽の場合、右項を評価しないため、JavaScriptエラーを回避できています。

 チェックボックスの数と各プロパティの参照結果をまとめると、次のようになります。

チェックボックス数とプロパティの参照結果(○=オブジェクトか数値か真偽値が返る)
プロパティ複数1個0個
document
document.form1
document.form1.sentakuChkundefined
document.form1.sentakuChk.lengthundefinedエラー
document.form1.sentakuChk[0]undefinedエラー
document.form1.sentakuChk[0].checkedエラーエラー
document.form1.sentakuChk.checkedundefinedエラー

 未定義(undefined)のプロパティから、さらに下位のプロパティを参照するときにJavaScriptエラーが発生しています。ブラウザのアドレスバーに、javascript:alert(document.form1.sentakuChk);等と打ち込んで確認することもできます。

テストケースの修正例

 実務では、コードの修正に伴い、テスト仕様書も修正する必要があるでしょう。データ表示件数が複数の時、1件の時、0件の時を分けてテストケースにするのがいいでしょう。

承認ボタン押下時のテストケース例
テストケース期待結果
表示データ複数・選択数複数該当データが「承認済み」に切り替わる
表示データ複数・選択数1件該当データが「承認済み」に切り替わる
表示データ複数・選択数0件入力エラー
表示データ1件・選択数1件該当データが「承認済み」に切り替わる
表示データ1件・選択数0件入力エラー
表示データ0件入力エラー

最後に

 このバグは、多くのWebプログラマが一度はハマったことのあるバグではないでしょうか。正常系以外のテストで「0件」のケースを想定するのは基本ですが、「1件」のケースは漏れやすく、バグの発見が遅れることがあるので注意が必要です。

 Struts等で利用されるJakarta commons validatorライブラリ内のJavaScript関数validateRequired()は、セレクトボックスやラジオボタンにも対応する汎用的な必須チェック用関数です。エラーメッセージ表示後に未入力・未選択のフォーム部品をフォーカスする機能も備わっています。以下のURLでソースコードが閲覧できます。他の関数も呼び出しているため理解しにくいところもありますが、一読されることをお勧めします。

追記:DOMを利用した修正

 今回のバグは、getElementsByName()メソッドを利用するとより簡単に修正できます。getElementsByName()メソッドは、指定したname属性値を持つフォーム部品を、要素のリストで返します。以下のコードで、チェックボックスの個数にかかわらず対応できます。

getElementsByNameメソッドを利用した修正ソース
function check() {
  // var sentakuChk = document.form1.sentakuChk;
  var sentakuChk = document.getElementsByName('sentakuChk');
  for (var i=0; i<sentakuChk.length; i++) {
    if (sentakuChk[i].checked) {
      return true;
    }
  }
  alert("1件も選択されていません。");
  return false;
}

 ただし、getElementsByName()メソッドはDOMのAPIであり、古いブラウザ(IE4以前)では正しく動作しません。しかし2008年現在、IE4以前のブラウザのシェアは1%未満のようであり、無視できるレベルかもしれません。システム要件が「IE5以上対応。IE4でJavaScriptエラーが出てもかまわない。」ということであれば、getElementsByName()メソッドを利用するのが良さそうです。

修正履歴

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

山城拓明(ヤマシロヒロアキ)

Web系SE。某企業にてWebシステム開発や新人Java研修講師を担当。Webアプリケーション開発における「よくあるハマるバグ」をまとめ、著書「バグ攻略で極めるWeb開発のツボ」(翔泳社)を出版。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/2544 2008/06/17 01:25

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング