jQuery

jQueryにてチェックボックスの状態を取得する


 よくWebアプリケーションで一覧表があると、それぞれのレコード(行)の頭にチェックボックスがついていて、チェックしたものをまとめて更新したり削除したりするようなUIを見かける。そして必ずと言って良いほどそれらチェックボックスの全てにチェックを入れたり外したりする操作ができるようになっている。
 その操作の手段としては[全選択][全解除]というボタンが用意されていたり、ボタンの代わりに全選択/全解除用のチェックボックスが見出し欄に設けてあったりする。どちらの場合でもjQureyを知らなかった時には実装するのはそこそこ大変だったが、jQueryを使えば簡単にできる。ところが後者の場合にちょっと躓いてしまったので整理してみたい。
 後者の場合というのは、全選択/全解除用のチェックボックスがクリックされた時に、チェックの状態によって全選択するか全解除するかを決める。だが、チェックボックスのチェック状態を取得しようとして以下のようなコードを書くと動きそうなのだがうまくいかない。

1
2
3
4
5
$(function(){
    $("#checkAll").click(function() {
        $("#anyForm :checkbox").attr("checked", $("#checkAll").attr("checked"));
    });
});

 オブジェクトの属性は .attr() メソッドで取得すると覚えていた。ところが公式のドキュメントをよく読んでみると、オブジェクトの属性(プロパティ)は .prop() で取得した方が良いようだ。以前はうまくいっていたと思っていたのはボタンで実装していたからだった。公式ドキュメントの一部を抜粋して意訳しよう。

jQuery1.6より前のバージョンでは .attr() メソッドで属性を返す時にプロパティを考慮することがあり、時として矛盾した動作をすることがあった。1.6以降のバージョンでは、 .prop() メソッドが厳密にプロパティを返し、その一方で .attr() メソッドは属性を返す。 (中略)
W3Cの仕様によると、checked属性は二値なので値があるときはtrue、値が無いか空の場合はfalseである。二値の属性は全て同様である。

尚、公式ドキュメントにはさらに記法による振る舞いの比較表が掲載されている。

コード例jQueryバージョン返される値
elem.checkedtrue(可変)
$(elem).prop("checked")1.6以降true(可変)
elem.getAttribute("checked")“checked”(初期状態・不変)
$(elem).attr("checked")1.6.0“checked”(初期状態・不変)
$(elem).attr("checked")1.6.1以降“checked”(可変)
$(elem).attr("checked")1.6より前true(可変)

 これを見る限り以前は動いていたというのは錯覚ではなかったようだ。つまり、もしjQueryのバージョン1.6以降を利用しているのなら、先ほどのコードは次のように書かなければならないということになる。

1
2
3
4
5
$(function(){
    $("#checkAll").click(function() {
        $("#anyForm :checkbox").prop("checked", $("#checkAll").prop("checked"));
    });
});





デモ
お飲み物
ビール(中瓶)
日本酒(1合)
焼酎 麦・芋(グラス)
ウィスキー(シングル)
ワイン 赤・白(グラス)


jQueryで階層を選択する



階層を選択する方法としては次の4種類が基本。言葉で説明するよりも視覚的に示した方が分かりやすいだろう。子供とか子孫とか兄弟とかいう言い方が英語の和訳で分かりづらい。なので意訳してみた。

Aに直接ぶら下がっているBだけを選択(子供)
Aより下の階層にある全てのBを選択(子孫)
Aと同じ階層で直後に続くBだけを選択(隣接)
Aと同じ階層の全てのBを選択(兄弟)

A
 
 
 
B
 
B
 
 
 
A
B
 
 
 
B
 
 
 
B
B
 
 
B
 

jQueryで全ての要素を選択する “*”


全ての要素を選択する。
尚、このセレクタを使用すると動作が非常に遅くなるので注意。(セレクタ単独で使用する場合を除く)

次のデモは現在表示されているページ内の全ての要素(headやbodyも含めて)の数を数える。
ブラウザのアドオンが自動的にsytleやlinkなどの要素を追加している場合はそれらも数えてしまう。


1
2
3
4
5
6
7
$(function(){
    $("#btnDemo1").click(function(){
        var elementCount = $("*").addClass("demo").length;
        alert(elementCount + " 個の要素があります。");
        $("*").removeClass("demo");
    });
});

一方、次のデモは特定の要素に含まれる要素の数を数える。

1
2
3
4
5
6
7
$(function(){
    $("#btnDemo2").click(function(){
        var elementCount = $("#test").find("*").addClass("demo").length;
        alert(elementCount + " 個の要素があります。");
        $("#test").find("*").removeClass("demo");
    });
});

WEBアプリで保存忘れを防止するチェック用スクリプト


よくWEBアプリケーションを利用していると思わず感心してしまうUIに出くわすことがある。例えばある大手SNSのプロフィール設定画面などがそれだ。プロフィールをいろいろいじっていてやっぱり止めたということはあるだろう。でも逆にうっかり保存しないでリンクをクリックしてしまい、せっかく書いた内容がパーになってしまうというケースもある。

ところが先ほどのSNSでは、保存前の状態で内容に変更があると、別の画面を開こうとした時に確認ダイアログが表示されるのだ。初めて見たときはなるほどと思った。これなら確かにうっかり保存し忘れるということも防げる。優れたUIだと思う。

ではこれを自分で実装してみたいと思った時、どうするか。まず最初に思いつくのはフォーム内のすべての項目の、変更前の値を保持しておき、ボタンが押されたりリンクがクリックされた時に全ての項目について現在の値と変更前の値とを比較するという方法である。愚直だが確実だ。しかし、項目が10個程度の編集画面であれば良いが、100ぐらいを超えるとそのやり方では正直厳しい。

そこで一つの例として、jQueryの serialize というメソッドを使ったやり方を紹介したい。このメソッドはフォームの内容をいわゆる Query String に変換してくれるものだ。データの型は文字列なので保持も比較も簡単だ。

例えば次の例はよくある予定管理のWEBアプリだと思っていただきたい。
フォームの内容を適当に編集してから画面上のどこでも良いのでリンクをクリックしてみて欲しい。
もし、何も変更点がなければそのままリンク先のページを開くだろう。
だが、何かしら変更されている場合は確認ダイアログが表示され、OKを押せばリンク先を開き、キャンセルを押せば元の画面のままのはずだ。


日時
2012年10月23日(火)
分 ~
予定
場所
詳細
公開設定


これは具体的には次のようなスクリプトを書いている。
(1) 最初に表示したタイミングでフォームの内容を文字列に変換してbeforeという変数に保持しておく。
(2) リンク(ボタンにすることも可能)がクリックされたタイミングで、もう一度フォームの内容を文字列に変換してafterという変数に保持しておく。
(3) before と after を比較し、異なっていれば警告を出す。
ちなみに文字列化したフォームの内容は次のようなものである。フォームの内容を変更すると文字列も変化する様子が確認できるだろう。
1
2
3
4
5
6
7
8
9
10
11
var before = "";
$(document).ready(function() {
    before = $("#frm_my_form").serialize(); // (1)
    $("a").click(function() {
        var after = $("#frm_my_form").serialize(); // (2)
        if (before != after) {
            return confirm("保存されてませんがよろしいですか?"); // (3)
        }
        return true;
    });
});
アーカイブ