1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AngularJS での複数チェックボックスの処理

Last updated at Posted at 2015-12-07

※AngularJS 1.4.8 です

AngularJSで、複数チェックボックスの処理するのがどうもよくわからなかったので初心者的メモ。
例えば「どれかチェック必須」とか「2つ以上チェック必須」とかがググってもよくわからなかったので、コントローラを自作してしまった。

例えば Twitter Bootstrap を使ってるとして、1つ以上チェックしてなければ form-grouphas-error のclassを付けたいという場合。

JavaScript側(コントローラ)
app.controller('checkBoxGroup', ['$scope', '$element', '$parse', function ($scope, $element, $parse) {
    // html の方で「self」という文字で状態を検出できるようにする
    var self = {
        touched: false,
        required: (undefined != ($element.attr('required') || $element.attr('ng-required'))),
        values: []
    };

    $scope.self = self;

    // 配下にある ng-model を取得
    $element.find('[ng-model]').each(function() {
        var item = angular.element(this);

        if (item.is(':checked') && !item.attr('ng-checked')) {
            // checked があればスコープに割当て
            $parse(item.attr('ng-model')).assign($scope, true);

            // 値を追加
            self.values.push(item.val());
        }

        // クリックされた場合
        item.on('click', function() {
            // 一度でも触れば touched を true に
            if (false == self.touched) {
                self.touched = true;
            }

            if (item.is(':checked')) {
                // 値を追加
                self.values.push(item.val());
            } else {
                // 値を削除
                var i = self.values.indexOf(item.val());
                if (i >= 0) {
                    self.values.splice(i, 1);
                }
            }
        });
    });
}]);
HTML側
<div class="form-group" ng-controller="checkBoxGroup" ng-class="{'has-error': self.required && self.touched && self.values.length < 1}" required>
    <label class="control-label">どれかチェックしてね</label>
    <div class="checkbox">
        <label><input type="checkbox" name="chk[]" value="項目1" ng-model="chk1" ng-required="self.required && self.values.length < 1">項目1</label>
        <label><input type="checkbox" name="chk[]" value="項目2" ng-model="chk2" ng-required="self.required && self.values.length < 1">項目2</label>
        <label><input type="checkbox" name="chk[]" value="項目3" ng-model="chk3" ng-required="self.required && self.values.length < 1" checked>項目3</label>
        <label><input type="checkbox" name="chk[]" value="項目4" ng-model="chk4" ng-required="self.required && self.values.length < 1">項目4</label>
    </div>
</div>
  • JavaScript側では ng-controller が指定された要素内にあるチェックボックスを検出して、HTML側でチェック状態が読めるように処理をしてる。
  • HTML側ではJavaScriptで処理されたチェックボックスの状態(この場合 self という変数)を使って監視してる。
    • self.touched で「1度でもクリック(チェック)されれば」という処理を監視して、初期状態では何もしないようにしてる。
    • required または ng-required があれば配下のチェックボックスを必須項目とする。
  • self.values.length < 1 により「1つ以上チェックされていなければ」という条件になる。
    2つ以上なら self.values.length < 2
  • チェックボックスの ng-model の名前はユニークにする必要がある。
  • ついでに、チェックボックスに checked があればデフォルトでチェックを入れる。
    • AngularJS管理下では checked ではなく ng-init="ngModel名=true" みたいにしないとデフォルトで checked にならないので。

追記

「AngularJS管理下では checked が効かない」という点について、input type="text" とかの value とか selectselected とかも効かないようなので以下のようなスニペットも作ってみた。
手探りなのでこれも正解かどうかはわからない。

// さいしょ
var app = angular.module('app', []);

// 直後にこれ実行しておく
app.run(['$rootScope', '$rootElement', '$parse', function($rootScope, $rootElement, $parse) {
    $rootElement.find('[ng-model]').each(function(i, e) {
        var item = angular.element(this);
        var type = item.attr('type')||this.tagName.toLowerCase();

        if (/^(checkbox|radio)$/.test(type)) {
            if (item.is(':checked') && !item.attr('ng-checked')) {
                $parse(item.attr('ng-model')).assign($rootScope, true);
            }
        } else if (item.val()) {
            $parse(item.attr('ng-model')).assign($rootScope, item.val());
        }
    });
}]);

普通に一般的な機能なので、たぶん車輪の再開発してるんじゃないかと思うけど・・・w

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?