すべて選択

よく、業務系なアプリにありがちだけど、一覧画面に各行の
先頭にチェックボックスがついてて、選択した行に対して
何かしらのアクションをする(削除とか)なんてのがある。
用途にもよるけど、だいたいそんな画面には「すべて選択」
とかってボタンがついてて一括チェック機能がついてたりする。

たいしたデータ量でなければどうってないんだけど、開発環境
のせいか、1000件近いデータが表示されていて、「すべて選択」
を押すと、2〜3秒固まってしまう。
ちなみにFireFoxで試したら元が速いので固まることはまったくなかった。
あくまでIE上での話。

そんなときの解決方法はページング機能をつけて20件くらい表示
したらいいんだろうけど。業務都合なのかもともと運用上は
そんな件数にならないよなのかわからないけどついてない。

で、処理してるJSみたら、こうなっていた。

var LIMIT = 1000;//ここはPHPで数字を設定しているっぽい
for (var i = 0; i < LIMIT; i++) {
    document.getElementById('chk_' + i).checked = true;
}
<form name="frm">
  <table>
    <tr>
      <td><input type="checkbox" id="chk_0" name="chk_0" /></td>
      <td><input type="textbox" id="text_0" name="text_0" /></td>
    </tr>
    <tr>
      <td><input type="checkbox" id="chk_1" name="chk_1" /></td>
      <td><input type="textbox" id="text_1" name="text_1" /></td>
    </tr>
    <tr>
      <td><input type="checkbox" id="chk_2" name="chk_2" /></td>
      <td><input type="textbox" id="text_2" name="text_2" /></td>
    </tr>
    :
    :
    <tr>
      <td><input type="checkbox" id="chk_999" name="chk_999" /></td>
      <td><input type="textbox" id="text_999" name="text_999" /></td>
    </tr>
  </table>
</form>

という感じになっていた。
(HTMLもname属性とid属性が同じなのもちょっと気になったけどそれはちょっとおいておく)
ループ毎にdocument.getElementByIdでElement取得している。
毎回検索が走ってるんだからそれは遅い。

書き直してみたその1

var frm = document.getElementsByName('frm')[0];
for (var i = 0; i < LIMIT; i++) {
  frm['chk_' + i].checked = true;
}

最初にform要素をとってきて配列記法でループしてみた。
結果は変わらないどころか元のより遅かった。
Form外の要素が多い場合には有効だったかもしれないけど
今回の場合はForm内の要素がオーバーヘッドになっているので
まったく有効な手段ではなかった。

書き直してみたその2

var input = document.getElementsByTagName('input');
var len = input.length;
for (var i = 0; i < len; i++) {
    var elm = input[i];
    if(elm.type == 'checkbox'){
        elm.checked = true;
    }
}

input属性の要素をとってきて、その中でtype属性がcheckboxの場合に処理を
行うようにした。
毎回のtype判定がある上にトータルのループ数は他に比べて倍になるので
いかがなものかと思ったけど上の2つよりもはるかに速い。
やっぱり、検索のコストってすごく高いんだな。

まとめると

ページングを導入できるところはしましょう。
ループ内でdocument.getElementByIdは遅いので使わないほうがいい。
ただ、FireFoxでみると、その2より元のほうが速いんだよな。
IEのバグでID属性とname属性両方見に行ってるとかその辺になんかあるのかな?
その辺は別の機会にぜひとも調べてみよう。

今回はform内のinputがチェックボックスとテキストの2つ(x1000)だったけど
これがもっと多いとその分ループは増えるから汎用的に有効な手段ではない。
場合によっていろいろな書き方してよい方法を見つけるべきだな。


検証に使ったソース(すごくいい加減)
http://www.daisun-labs.org/test/checkbox.php
一応アラートで処理時間(ミリ秒)がでるようにしてある。