FE-problem-collection icon indicating copy to clipboard operation
FE-problem-collection copied to clipboard

AngularJS 实现 checkbox 全选、反选的思考

Open mayufo opened this issue 8 years ago • 4 comments

需求

1 还有个总的 checkbox 负责全选和反选 2 当每一项开头都选中 checkbox 的时候,上面的全选自动选上 3 当全选后,取消其中一项的 checkbox ,全选取消

实践

我表示刚开始我是不会的!!!

思路1 上网查找 demo

然后开始查资料

发现个不错的网上案例 like this > demo

感觉非常符合我的需求,但是看到 demo。

缺点: 没玩几下就发现无法符合需求2、3。但是貌似1 是可以实现的。

思路2 ng-checked

开始查了下 checkbox 在 AngularJS 里面的用法和 ng-checked ,发现如果用了 ng-checked 目测可以实现

html

<div ng-controller="myController">
    <label for="flag">全选
        <input id="flag" type="checkbox" ng-model="select_all" ng-click="selectAll()">
    </label>
    <ul>
        <li ng-repeat="i in list">
            <input type="checkbox" ng-model="m[i.id]" ng-checked = "select_one" ng-click="selectOne(m[i.id])">
            <span>{{i.id}}</span>
        </li>
    </ul>
</div>

js

var app = angular.module('myApp',[]);
app.controller('myController', ['$scope', function ($scope) {
    $scope.list = [
        {'id': 101},
        {'id': 102},
        {'id': 103},
        {'id': 104},
        {'id': 105},
        {'id': 106},
        {'id': 107}
    ];
    $scope.m = [];
    $scope.checked = [];
    $scope.selectAll = function () {
        if($scope.select_all) {
            $scope.select_one = true;
            $scope.checked = [];
            angular.forEach($scope.list, function (i, index) {
                $scope.checked.push(i.id);
                $scope.m[i.id] = true;
            })
        }else {
            $scope.select_one = false;
            $scope.checked = [];
            $scope.m = [];
        }
        console.log($scope.checked);
    };
    $scope.selectOne = function (select) {
        angular.forEach($scope.m , function (i, id) {
            var index = $scope.checked.indexOf(id);
            if(i && index === -1) {
                $scope.checked.push(id);
            } else if (!i && index !== -1){
                $scope.checked.splice(index, 1);
            };
        });
        if ($scope.list.length === $scope.checked.length) {
            $scope.select_all = true;
        } else {
            $scope.select_all = false;
        }
        console.log($scope.checked);
    }
}]);

缺点 参考 not-binding-to-ng-checked-for-checkboxes

大概意思说 如果你用了 ng-checked 就是默认它最初定义就是 true, 因此就没有必要使用 ng-model 了。简单说来就是 ng-model 和 ng-checked 不需要同时用。

看来是能用 ng-click 或者 ng-change 了

思路3 给数组里面每一个 list 绑定 checked 的属性

这个想法也是联想到公司之前的一个大牛的写的一个关于 checkbox 的指令。

html

<div ng-controller="myController">
    <label for="flag">全选
        <input id="flag" type="checkbox" ng-model="select_all" ng-change="selectAll()">
    </label>
    <ul>
        <li ng-repeat="i in list">
            <input type="checkbox" ng-model="i.checked" ng-change="selectOne()">
            <span>{{id}}</span>
        </li>
    </ul>
</div>

js

var app = angular.module('myApp',[]);
app.controller('myController', ['$scope', function ($scope) {
    $scope.list = [
        {'id': 101},
        {'id': 102},
        {'id': 103},
        {'id': 104},
        {'id': 105},
        {'id': 106},
        {'id': 107}
    ];
    $scope.m = [];
    $scope.checked = [];
    $scope.selectAll = function () {
        if($scope.select_all) {
            $scope.checked = [];
            angular.forEach($scope.list, function (i) {
                i.checked = true;
                $scope.checked.push(i.id);
            })
        }else {
            angular.forEach($scope.list, function (i) {
                i.checked = false;
                $scope.checked = [];
            })
        }
        console.log($scope.checked);
    };
    $scope.selectOne = function () {
        angular.forEach($scope.list , function (i) {
            var index = $scope.checked.indexOf(i.id);
            if(i.checked && index === -1) {
                $scope.checked.push(i.id);
            } else if (!i.checked && index !== -1){
                $scope.checked.splice(index, 1);
            };
        })

        if ($scope.list.length === $scope.checked.length) {
            $scope.select_all = true;
        } else {
            $scope.select_all = false;
        }
        console.log($scope.checked);
    }
}]);

推荐第三种方法!以上

参考:

  • http://www.cnblogs.com/wohenxion/p/4624218.html
  • https://docs.angularjs.org/api/ng/directive/ngChecked
  • http://karatejb.blogspot.com/2015/07/angularjs-checkbox.html
  • http://stackoverflow.com/questions/16601018/angularjs-ng-model-not-binding-to-ng-checked-for-checkboxes

mayufo avatar Aug 07 '16 10:08 mayufo

补充: 实现 checkbox 全选和反选的思路: 第一,由于后端数据不会提供一个空的 checkbox 列给我们,所以我们需要根据返回的长度初始化一个数组,并在 ng-repeat 的时候,赋值为 false。 第二,考虑到要为后端返回选中的 id 数组, 此时对相应的 checkbox 设置 ng-true-value="{{i.id}}" 第三,就是考虑,全选,反选的例子,其实很简单,全选的话,就为数组赋值所有的 id 数组,使用数组 map方法,反之,返回一个 false 数组 第四,当有 checkbox check 或 uncheck,你需要,改变控制全选和反选 checkbox 的行为,很简单使用 $watchCollection 方法监控数组变化,并使用数组 every 方法判断是否都不是 false 。

<div ng-app="myApp">
  <div ng-controller="myController">
      <label for="flag">全选
          <input id="flag" type="checkbox" ng-model="isAll" ng-click="checkAll()">
      </label>
      <ul>
          <li ng-repeat="i in list" ng-init="checkboxes[$index] = false">
              <input type="checkbox" ng-model="checkboxes[$index]" ng-true-value="{{i.id}}" ng-false-value="false">
              <span>{{i.id}}</span>
          </li>
      </ul>
      <button ng-click="getCheckedList()">get checked list</button>
  </div>
</div>
var app = angular.module('myApp',[]);

app.controller('myController', ['$scope', function ($scope) {

    $scope.list = [
        {'id': 101},
        {'id': 102},
        {'id': 103},
        {'id': 104},
        {'id': 105},
        {'id': 106},
        {'id': 107}
    ];

    $scope.checkboxes = new Array($scope.list.length);

    $scope.isAll = false;

    $scope.checkAll = function() {
         if ($scope.isAll) {
              $scope.checkboxes = $scope.list.map(function(item) {return item.id});
           } else {
              $scope.checkboxes = $scope.list.map(function(item) {return false});;
           }
    };

    $scope.$watchCollection('checkboxes', function(newC) {
          if (newC.every(function(item) {return item != false;})) {
              $scope.isAll = true;
          } else {
              $scope.isAll = false;
          }
    });

    $scope.getCheckedList = function() {
        alert($scope.checkboxes + ' ' +$scope.checkboxes.length );
        console.log($scope.checkboxes.filter(function(item) {return item;}));
    };

}]);

jsfiddle: https://jsfiddle.net/hjzheng/0nq252so/1/

hjzheng avatar Aug 07 '16 14:08 hjzheng

组件库带checkbox的表格有相应功能,可以参考

kuitos avatar Aug 07 '16 14:08 kuitos

不推荐第三种方法,原始数据引入脏属性,表单提交时可能需要额外处理

kuitos avatar Aug 07 '16 14:08 kuitos

选中的内容还要追加到一个input标签里面又该如何实现呢?

nearxu avatar Aug 25 '16 01:08 nearxu