お手軽高機能!Closure UI【goog.ui.Checkbox】

2012.11.20

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Closure Libraryに用意されている「goog.ui.Checkbox」は、3値(true, false, null)からなる状態(checked, unchecked, undetermined)を持つチェックボックスコンポーネントです。

デモ

Checkboxの持つ三種の状態が確認できるデモです。全てではないいくつかの「選択項目」がチェックされていると「全選択」チェックボックスが第三の状態「UNDETERMINED」となります。

全選択
選択項目1
選択項目2
選択項目3
選択項目4

デモコード

index.html
<!DOCTYPE html>
<html>
  <head>
    <title>goog.ui.Checkbox</title>
    <meta charset=utf-8>
    <script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>
    <script>
      goog.require('goog.dom');
      goog.require('goog.events');
      goog.require('goog.ui.Checkbox');
      goog.require('goog.ui.Checkbox.State');
    </script>
    <link rel="stylesheet" href="http://closure-library.googlecode.com/svn/trunk/closure/goog/css/common.css">
    <link rel="stylesheet" href="http://closure-library.googlecode.com/svn/trunk/closure/goog/css/checkbox.css">
  </head>
  <body>
    <div><span id="all" class="goog-checkbox"></span>全選択</div>
    <div id="items" style="margin-left: 1em;">
      <div><span class="item goog-checkbox"></span>選択項目1</div>
      <div><span class="item goog-checkbox"></span>選択項目2</div>
      <div><span class="item goog-checkbox"></span>選択項目3</div>
      <div><span class="item goog-checkbox"></span>選択項目4</div>
    </div>
    <script>
      var all = new goog.ui.Checkbox();
      all.decorate(goog.dom.getElement('all'));
      all.setLabel(all.getElement().parentNode);
      
      var elements = goog.dom.getElementsByTagNameAndClass('span', 'item', goog.dom.getElement('items'));
      var items = [];
      goog.array.forEach(elements, function(element) {
        var item = new goog.ui.Checkbox();
        item.decorate(element);
        item.setLabel(element.parentNode);
        items.push(item);
      });
  
      var all_changeHandler = function(event) {
        goog.array.forEach(items, function(item, index, array) {
          item.setChecked(all.getChecked());
        });
      };
      
      var item_changeHandler = function(event) {
        var firstChecked;
        var same = goog.array.every(items, function(item, index, array) {
          if (index < 1) {
            firstChecked = item.getChecked();
            return true;
          } else
            return firstChecked == item.getChecked();
        });
        all.setChecked(same ? event.target.getChecked() : goog.ui.Checkbox.State.UNDETERMINED);
      };
      
      all.addEventListener(goog.ui.Component.EventType.CHANGE, all_changeHandler);
      goog.array.forEach(items, function(item) {
        item.addEventListener(goog.ui.Component.EventType.CHANGE, item_changeHandler);
      });
    </script>
  </body>
</html>

使い方

Checkboxコンポーネントは、生成したインスタンスを対象となる要素に「描画(render)」もしくは「装飾(decorate)」して用います。

Closure Libraryのロード

    <script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>
    <script>
      goog.require('goog.dom');
      goog.require('goog.events');
      goog.require('goog.ui.Checkbox');
      goog.require('goog.ui.Checkbox.State');
    </script>
6行目
Closure Libraryのbase.jsをロードします。
(このbase.jsをロードした場合には多くのスクリプト群がロードされる為、リリースするWebアプリケーションではこの形式は取りません。通常はClosure Libraryによる依存性管理およびClosure Compilerによるスクリプトの統合が用いられます。)
7~12行目
必要とするClosure Libraryを宣言します。ここで「require」したものがグローバル変数領域に展開されます。

標準スタイルのロード

    <link rel="stylesheet" href="http://closure-library.googlecode.com/svn/trunk/closure/goog/css/common.css">
    <link rel="stylesheet" href="http://closure-library.googlecode.com/svn/trunk/closure/goog/css/checkbox.css">
13, 14行目
Checkboxコンポーネントに標準で用意されているスタイル定義をロードします。UIコンポーネントには専用のスタイルが定義されたCSSファイルが用意されているものがあります。通常はクラス名と同様の名称(goog.ui.Checkbox→checkbox.css)になっているので直ぐに見つかると思います。

画面要素

    <div><span id="all" class="goog-checkbox"></span>全選択</div>
    <div id="items" style="margin-left: 1em;">
      <div><span class="item goog-checkbox"></span>選択項目1</div>
      <div><span class="item goog-checkbox"></span>選択項目2</div>
      <div><span class="item goog-checkbox"></span>選択項目3</div>
      <div><span class="item goog-checkbox"></span>選択項目4</div>
    </div>

Checkboxの生成および描画

      var all = new goog.ui.Checkbox();
      all.decorate(goog.dom.getElement('all'));
      all.setLabel(all.getElement().parentNode);
25行目
「全選択」チェックボックス用のCheckboxコンポーネントインスタンスを生成しています。
26行目
「ID:all」の要素(span)を、Checkboxコンポーネントで装飾(decorate)しています。
27行目
Checkboxコンポーネントの親のノードをチェックボックスのラベルとして設定しています。この設定により、親のノード「div」のクリックも検知され、チェックボックスの選択状態が変更されます。
      var elements = goog.dom.getElementsByTagNameAndClass('span', 'item', goog.dom.getElement('items'));
      var items = [];
      goog.array.forEach(elements, function(element) {
        var item = new goog.ui.Checkbox();
        item.decorate(element);
        item.setLabel(element.parentNode);
        items.push(item);
      });
29~36行目
「選択項目」の要素に対してCheckboxコンポーネントを装飾しています。「全選択」チェックボックスが変更された時の処理に利用する為、Checkboxコンポーネントのインスタンスを一時変数「items」に保持しています。

イベントハンドラの定義

      var all_changeHandler = function(event) {
        goog.array.forEach(items, function(item, index, array) {
          item.setChecked(all.getChecked());
        });
      };
38~42行目
「全選択」チェックボックスがクリックされた際のイベントハンドラを定義しています。全ての「選択項目」の選択状態を「全選択」チェックボックスと同じ状態にする処理を行います。
      var item_changeHandler = function(event) {
        var firstChecked;
        var same = goog.array.every(items, function(item, index, array) {
          if (index < 1) {
            firstChecked = item.getChecked();
            return true;
          } else
            return firstChecked == item.getChecked();
        });
        all.setChecked(same ? event.target.getChecked() : goog.ui.Checkbox.State.UNDETERMINED);
      };
[/javascript]
<dl>
<dt>44~54行目</dt>
<dd>「選択項目」のチェックボックスが変更された時のイベントハンドラを定義しています。全ての選択項目が同じ状態であれば「全選択」チェックボックスをその状態に、異なっていれば「全選択」チェックボックスの状態を「UNDETERMINED」とします。</dd>
</dl>
<h3>リスナへの登録</h3>

      all.addEventListener(goog.ui.Component.EventType.CHANGE, all_changeHandler);
      goog.array.forEach(items, function(item) {
        item.addEventListener(goog.ui.Component.EventType.CHANGE, item_changeHandler);
      });
56~59行目
各Checkboxコンポーネントのリスナにイベントハンドラを追加しています。

まとめ

ブラウザネイティブのチェックボックスと違い、状態「UNDETERMINED」を持つのが特徴ですね。テーブルを用いたリスト表示などにおいて、全ての行の選択状態を制御する「全選択」チェックボックスとして使われるのが一般的でしょうか。ラベル文字列のクリックを検知するように設定できることも特徴的です。

参照