我认为您提供的示例解决方案将太多代码放入控制器中。控制器应该只关心列表,HTML/指令应该处理显示(包括显示全选复选框)。此外,所有状态更改都是通过模型进行的,而不是通过编写函数。
我在 Plunker 上制定了一个解决方案:http ://plnkr.co/edit/gSeQL6XPaMsNSnlXwgHt?p=preview
现在,控制器只是设置列表:
app.controller('MainCtrl', function($scope) {
$scope.list = [{
isSelected: true,
desc: "Donkey"
}, {
isSelected: false,
desc: "Horse"
}];
});
并且视图只是将它们呈现出来:
<div ng-repeat="elem in list">
<input type="checkbox" ng-model="elem.isSelected" /> {{elem.desc}}
</div>
对于 Select All 复选框,我创建了一个名为的新指令checkbox-all
:
<input checkbox-all="list.isSelected" /> Select All
就使用而言,这就是它,希望它很简单......除了编写那个新指令:
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);
};
});
该parts
变量将其分解为两部分,因此我可以从范围list.isSelected
中获取 的值,即每个对象中的属性。list
isSelected
我将该type="checkbox"
属性添加到输入元素,使其成为浏览器的真正复选框。这意味着用户可以点击它,标签到它等等。
我绑定onchange
事件而不是onclick
,因为可以通过多种方式更改复选框,包括通过键盘。onchange 事件在 a 中运行,scope.$apply()
以确保模型更改在最后得到消化。
最后,我$watch
将输入模型更改为复选框(最后一个true
允许我查看复杂对象)。这意味着如果用户或其他原因更改了复选框,则 Select All 复选框始终保持同步。这比编写大量的 ng-click 处理程序要好得多。
如果复选框同时被选中和未选中,那么我将主复选框设置为未选中并添加样式“灰色”(请参阅 参考资料style.css
)。该 CSS 样式基本上将不透明度设置为 30%,导致复选框显示为灰色,但仍可点击;您也可以使用 Tab 键并使用空格键更改其值。
我已经在 Firefox、Chrome 和 Safari 中进行了测试,但我手头没有 IE。希望这对你有用。