如何通过选择/取消选择所有功能和不确定值来获取angular.js复选框?

Jan*_*sen 27 javascript checkbox html5 tri-state-logic angularjs

我正在寻找与这些完全相同的东西(带有"父母"的三态复选框).但是使用该解决方案并不优雅,因为我现在不依赖于jQuery,而且我需要调用$ scope.$ apply以使模型识别自动(未)检查的复选框jQuery被点击.

这是angular.js的一个错误,它要求实现ng-indeterminate-value.但这仍然不会让我与所有孩子同步,这是我认为不应该成为我的控制器的一部分.

我正在寻找的是这样的:

  • 一个"ng-children-model"指令,语法如下:<input type="checkbox" ng-children-model="child.isSelected for child in listelements">.将计算布尔值列表,如果选择0,则复选框为false.如果全部选中 - >复选框为true.否则 - >复选框不确定.
  • 在我的控制器中,我会有这样的事情: $scope.listelements = [{isSelected: true, desc: "Donkey"},{isSelected: false, desc: "Horse"}]
  • 复选框将照常使用<tr ng-repeat="elem in listelements"><td><input type="checkbox" ng-model="elem.isSelected"></td><td>{{elem.desc}}</td></tr>.
  • 据我了解,浏览器将确定单击的不确定复选框进入哪个状态.

Pir*_*ran 20

我认为您提供的示例解决方案会将太多代码放入控制器中.控制器应该只是担心列表,HTML /指令应该处理显示(包括显示全选复选框).此外,所有状态更改都是通过模型,而不是通过编写函数.

我在Plunker上整理了一个解决方案:http://plnkr.co/edit/gSeQL6XPaMsNSnlXwgHt?p = preview

现在,控制器只是设置列表:

app.controller('MainCtrl', function($scope) {
    $scope.list = [{
        isSelected: true,
        desc: "Donkey"
    }, {
        isSelected: false,
        desc: "Horse"
    }];
});
Run Code Online (Sandbox Code Playgroud)

并且视图只是将它们渲染出来:

<div ng-repeat="elem in list">
  <input type="checkbox" ng-model="elem.isSelected" /> {{elem.desc}}
</div>
Run Code Online (Sandbox Code Playgroud)

对于Select All复选框,我创建了一个名为的新指令checkbox-all:

  <input checkbox-all="list.isSelected" /> Select All
Run Code Online (Sandbox Code Playgroud)

就使用而言,这就是它,希望简单......除了编写新的指令:

app.directive('checkboxAll', function () {
  return function(scope, iElement, iAttrs) {
    var parts = iAttrs.checkboxAll.split('.');
    iElement.attr('type','checkbox');
    iElement.bind('change', function (evt) {
      scope.$apply(function () {
        var setValue = iElement.prop('checked');
        angular.forEach(scope.$eval(parts[0]), function (v) {
          v[parts[1]] = setValue;
        });
      });
    });
    scope.$watch(parts[0], function (newVal) {
      var hasTrue, hasFalse;
      angular.forEach(newVal, function (v) {
        if (v[parts[1]]) {
          hasTrue = true;
        } else {
          hasFalse = true;
        }
      });
      if (hasTrue && hasFalse) {
        iElement.attr('checked', false);
        iElement.addClass('greyed');
      } else {
        iElement.attr('checked', hasTrue);
        iElement.removeClass('greyed');
      }
    }, true);
  };
});
Run Code Online (Sandbox Code Playgroud)

parts变量打破了list.isSelected成两个部分,这样我就可以得到的值list从范围,涉及的isSelected财产中的每个对象.

我将type="checkbox"属性添加到input元素,使其成为浏览器的真正复选框.这意味着用户可以点击它,选项卡等等.

我绑定onchange事件而不是onclick,因为可以通过多种方式更改复选框,包括通过键盘.onchange事件在a内部运行,scope.$apply()以确保模型更改在最后被消化.

最后,我$watch输入模型更改复选框(最后一个true允许我观看复杂的对象).这意味着如果用户更改了复选框或出于其他原因,则"全选"复选框始终保持同步.这比编写大量的ng-click处理程序要好得多.

如果选中并取消选中复选框,则将主复选框设置为取消选中,并添加样式'greyed'(请参阅参考资料style.css).CSS样式基本上将不透明度设置为30%,导致复选框显示为灰色,但它仍然可以点击; 您还可以选中它并使用空格键更改其值.

我已经在Firefox,Chrome和Safari中进行过测试,但我没有手持IE浏览器.希望这适合你.


Mar*_*cok 20

由于您需要一种新类型/类型的组件,这听起来像是一个自定义指令的好例子.
由于父/主/三重复选框和各个双状态复选框需要相互交互,我建议使用一个带有自己的控制器的单个指令来处理逻辑.

<tri-state-checkbox checkboxes="listelements"></tri-state-checkbox>
Run Code Online (Sandbox Code Playgroud)

指示:

app.directive('triStateCheckbox', function() {
  return {
    replace: true,
    restrict: 'E',
    scope: { checkboxes: '=' },
    template: '<div><input type="checkbox" ng-model="master" ng-change="masterChange()">'
      + '<div ng-repeat="cb in checkboxes">'
      + '<input type="checkbox" ng-model="cb.isSelected" ng-change="cbChange()">{{cb.desc}}'
      + '</div>'
      + '</div>',
    controller: function($scope, $element) {
      $scope.masterChange = function() {
        if($scope.master) {
          angular.forEach($scope.checkboxes, function(cb, index){
            cb.isSelected = true;
          });
        } else {
          angular.forEach($scope.checkboxes, function(cb, index){
            cb.isSelected = false;
          });
        }
      };
      var masterCb = $element.children()[0];
      $scope.cbChange = function() {
        var allSet = true, allClear = true;
        angular.forEach($scope.checkboxes, function(cb, index){
          if(cb.isSelected) {
            allClear = false;
          } else {
            allSet = false;
          }
        });
        if(allSet)        { 
          $scope.master = true; 
          masterCb.indeterminate = false;
        }
        else if(allClear) { 
          $scope.master = false; 
          masterCb.indeterminate = false;
        }
        else { 
          $scope.master = false;
          masterCb.indeterminate = true;
        }
      };
      $scope.cbChange();  // initialize
    },
  };
});
Run Code Online (Sandbox Code Playgroud)

更改模板以满足您的需要,或使用带有templateUrl的外部模板.

该指令假定checkboxes数组包含具有isSelected属性和desc属性的对象.

Plunker.

更新:如果您希望指令仅呈现三重复选框,因此各个复选框都在HTML中(如@ Piran的解决方案),这是另一个类型的plunker变体.对于这个plunker,HTML将是:

<tri-state-checkbox checkboxes="listelements" class="select-all-cb">
</tri-state-checkbox>select all
<div ng-repeat="item in listelements">
   <input type="checkbox" ng-model="item.isSelected"> {{item.desc}}
</div>
Run Code Online (Sandbox Code Playgroud)


wld*_*nfr 5

这是皮兰解决方案的改进版本。使用.prop()而不是.attr()解决checked问题。

用法:

<div ng-repeat="elem in list">
    <input type="checkbox" ng-model="elem.isSelected" /> {{elem.desc}}
</div>
<ui-select-all items="list" prop="isSelected"></ui-select-all> Select all
Run Code Online (Sandbox Code Playgroud)