カテゴリー別アーカイブ: モデル

AngularJS チェックボックス主体のフォームを作成する

AngularJSを利用して, チェックボックス主体のフォームを作成する場合にいろいろはまったので備忘録的にまとめておきます.

ただし, チェックボックスをトグルボタン的に利用する(つまり, チェックされているかどうかが重要)ケースではなく, 例えば, 該当する項目をチェックしてサーバーに送信するといったフォームの場合(つまり, チェックされている値が重要) です.

1 . まとめてチェックの実装

チェックボックスが多い場合, この機能を実装することが多いですが, AngularJSであれば, モデルのバインドだけで実装可能なので, コントローラーが不要です.

<dl>
    <dt><input type="checkbox" ng-model="checkAll" /> Check All </dt>
    <dd>
        <input type="checkbox" ng-checked="checkAll" ng-model="values[0]" /> 0
       <input type="checkbox" ng-checked="checkAll" ng-model="values[1]" /> 1
      <input type="checkbox" ng-checked="checkAll" ng-model="values[2]" /> 2
    </dd>
</dl>

ポイントは, すべてチェックのためのチェックボックスにモデルをバインドして, チェックされる側のチェックボックスに ng-checkedディレクティブを記述して, すべてチェックのためのチェックボックスにバインドしたモデルを指定することです.

ただし, 1つ注意点があり, チェックされる側でモデルをバインドしている場合, すべてチェックでチェックを入れてもモデルが更新されないことです (上記のコードで言えば, valuesの配列).

したがって, チェックされている値を送信する場合などは, すべてチェックのためのチェックボックスに ng-changeでイベントハンドラを設定して, 関連するモデルを更新するか, リアルタイムに反映しなくてよいのであれば, 送信前などにチェックされている値をまとめてピックアップするか,です.

これは最もはまりやすいところではないかと思ったので真っ先にとりあげました (この記事の最後にデモへのリンクがあるので実際に確かめてみてください).

2. チェックされた値のng-repeat

この機能を実装すること (例えば, チェックされている値をわざわざリストなどにして表示する) は少ないのですが, もし実装する場合, ほぼ確実にはまるポイントがあります.

チェックボックスというのは, もともと複数の値を選択できるようにするためのUIです. したがって, そのモデルというのも, 構造をもつデータ型, つまり, 配列かプレインオブジェクトにすることが多いはずです. 特に, 順序性も保持したい場合は, 確実に配列を利用することになります.

具体的には, チェックボックスの数のサイズをもつ配列をモデルとして定義しておきます.

$scope.values = new Array(3);
<dl>
    <dt><input type="checkbox" ng-model="checkAll" /> Check All </dt>
    <dd>
        <input type="checkbox" ng-checked="checkAll" ng-model="values[0]" /> 0
       <input type="checkbox" ng-checked="checkAll" ng-model="values[1]" /> 1
      <input type="checkbox" ng-checked="checkAll" ng-model="values[2]" /> 2
    </dd>
</dl>
<ul>
    <li ng-repeat="value in values" ng-bind="value"></li>
<ul>

ここで, チェックをつけたり, はずしたりを繰り返すと重複した値が配列に格納されます(例 [true, false, true]).

ところが, ng-repeatでは重複する値があると,

Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys.

というエラーが発生してしまいます.

これを解決する方法としては, track by $indexを利用する方法があるそうなのですが….

この記事のデモ (この記事の最後にリンクあります) では, 配列に直接値を格納するのではなく, (ng-true-value) をキーに, ng-true-value / ng-false-value が値として入る連想配列 (プレインオブジェクト) ( = 構造化した値) を配列に格納することで値の重複を防ぎ, 上記のエラーを出さないようにしています.

解決策は他にもいろいろありそうですが, 最初に述べたように実際のフォームではわざわざリアルタイムに表示することもないので, ng-repeatの注意点としておさえておけばいいかなあと思います.

3. チェックの値を変更する

チェックされたときのデフォルトの値はtrue, そうでないときは, falseです. トグルボタン的に利用する場合はこれでよいかもしれないですが, サーバーサイドで処理する場合などは値を設定することの方が多いはずです.

値を変更するのは簡単で, ng-true-value / ng-false-valueディレクティブを利用することです.

<input type="checkbox" ng-model="values[0]" ng-true-value="ON" ng-false-value="OFF" /> ON / OFF

チェックされたときに, ng-true-valueの値がモデルに格納されます (上記のコードではvalues配列のインデックス0の要素). 逆に, チェックをはずしたときは, ng-false-valueの値がモデルに格納されます. ただ, ng-false-valueの場合は, nullやundefinedにしたいと思ったのですが, その方法はわかりませんでした…

以上のエッセンスをおさえたサンプルコードがこちらです.

デモはこちらです.