如何响应点击AngularJS指令中的checkbox?
我有一个AngularJS 指令 ,呈现下列模板中的实体的集合:
<table class="table"> <thead> <tr> <th><input type="checkbox" ng-click="selectAll()"></th> <th>Title</th> </tr> </thead> <tbody> <tr ng-repeat="e in entities"> <td><input type="checkbox" name="selected" ng-click="updateSelection($event, e.id)"></td> <td>{{e.title}}</td> </tr> </tbody> </table>
正如你所看到的,它是一个<table>
,每行可以用自己的checkbox单独select,或者所有的行可以用位于<thead>
中的主checkbox一次select。 很经典的用户界面
什么是最好的办法:
- select一行(即选中checkbox时,将所选实体的ID添加到内部数组中,并将CSS类添加到包含实体的
<tr>
以反映其所选状态)? - 一次select所有行? (即对
<table>
中的所有行执行之前描述的操作)
我目前的实施是添加一个自定义控制器到我的指令:
controller: function($scope) { // Array of currently selected IDs. var selected = $scope.selected = []; // Update the selection when a checkbox is clicked. $scope.updateSelection = function($event, id) { var checkbox = $event.target; var action = (checkbox.checked ? 'add' : 'remove'); if (action == 'add' & selected.indexOf(id) == -1) selected.push(id); if (action == 'remove' && selected.indexOf(id) != -1) selected.splice(selected.indexOf(id), 1); // Highlight selected row. HOW?? // $(checkbox).parents('tr').addClass('selected_row', checkbox.checked); }; // Check (or uncheck) all checkboxes. $scope.selectAll = function() { // Iterate on all checkboxes and call updateSelection() on them?? }; }
更具体地说,我想知道:
- 上面的代码是属于一个控制器还是应该在
link
function? - 鉴于jQuery不一定存在(AngularJS不需要它),什么是做DOM遍历的最好方法? 如果没有jQuery,我很难select给定checkbox的父
<tr>
,或者select模板中的所有checkbox。 - 将
$event
传递给updateSelection()
看起来不太优雅。 没有更好的方式来检索刚刚被点击的元素的状态(选中/未选中)吗?
谢谢。
这是我一直在做这种事情的方式。 Angular倾向于支持对dom的声明式操作,而不是一个必需的操作(至less这是我一直在玩的方式)。
标记
<table class="table"> <thead> <tr> <th> <input type="checkbox" ng-click="selectAll($event)" ng-checked="isSelectedAll()"> </th> <th>Title</th> </tr> </thead> <tbody> <tr ng-repeat="e in entities" ng-class="getSelectedClass(e)"> <td> <input type="checkbox" name="selected" ng-checked="isSelected(e.id)" ng-click="updateSelection($event, e.id)"> </td> <td>{{e.title}}</td> </tr> </tbody> </table>
并在控制器中
var updateSelected = function(action, id) { if (action === 'add' && $scope.selected.indexOf(id) === -1) { $scope.selected.push(id); } if (action === 'remove' && $scope.selected.indexOf(id) !== -1) { $scope.selected.splice($scope.selected.indexOf(id), 1); } }; $scope.updateSelection = function($event, id) { var checkbox = $event.target; var action = (checkbox.checked ? 'add' : 'remove'); updateSelected(action, id); }; $scope.selectAll = function($event) { var checkbox = $event.target; var action = (checkbox.checked ? 'add' : 'remove'); for ( var i = 0; i < $scope.entities.length; i++) { var entity = $scope.entities[i]; updateSelected(action, entity.id); } }; $scope.getSelectedClass = function(entity) { return $scope.isSelected(entity.id) ? 'selected' : ''; }; $scope.isSelected = function(id) { return $scope.selected.indexOf(id) >= 0; }; //something extra I couldn't resist adding :) $scope.isSelectedAll = function() { return $scope.selected.length === $scope.entities.length; };
编辑 : getSelectedClass()
期待整个实体,但它被称为与实体的唯一身份证,现在已被纠正
处理checkbox时,我更喜欢使用ngModel和ngChange指令。 ngModel允许您将checkbox的选中/未选中状态绑定到实体上的一个属性:
<input type="checkbox" ng-model="entity.isChecked">
每当用户选中或取消选中checkbox时, entity.isChecked
值也会改变。
如果这是你所需要的,那么你甚至不需要ngClick或ngChange指令。 由于您有“全部选中”checkbox,您显然需要做的不仅仅是当某人选中某个checkbox时设置该属性的值。
在checkbox中使用ngModel时,最好使用ngChange而不是ngClick来处理checked和unchecked事件。 ngChange是为了这种场景而devise的。 它使用ngModelController进行数据绑定(它将一个监听器添加到ngModelController的$viewChangeListeners
数组中,数组中的监听器在模型值被设置后被调用,从而避免了这个问题 )。
<input type="checkbox" ng-model="entity.isChecked" ng-change="selectEntity()">
…在控制器中…
var model = {}; $scope.model = model; // This property is bound to the checkbox in the table header model.allItemsSelected = false; // Fired when an entity in the table is checked $scope.selectEntity = function () { // If any entity is not checked, then uncheck the "allItemsSelected" checkbox for (var i = 0; i < model.entities.length; i++) { if (!model.entities[i].isChecked) { model.allItemsSelected = false; return; } } // ... otherwise ensure that the "allItemsSelected" checkbox is checked model.allItemsSelected = true; };
同样,标题中的“全选”checkbox:
<th> <input type="checkbox" ng-model="model.allItemsSelected" ng-change="selectAll()"> </th>
…和…
// Fired when the checkbox in the table header is checked $scope.selectAll = function () { // Loop through all the entities and set their isChecked property for (var i = 0; i < model.entities.length; i++) { model.entities[i].isChecked = model.allItemsSelected; } };
CSS
什么是最好的方法…添加一个CSS类到
<tr>
包含实体,以反映其select的状态?
如果您使用ngModel方法进行数据绑定,则只需将ngClass指令添加到<tr>
元素即可在实体属性更改时dynamic添加或移除类:
<tr ng-repeat="entity in model.entities" ng-class="{selected: entity.isChecked}">
在这里看到完整的Plunker 。
Liviu的回答对我非常有帮助。 希望这不是坏的forms,但我做了一个小提琴 ,可以帮助别人在未来。
需要两个重要的部分是:
$scope.entities = [{ "title": "foo", "id": 1 }, { "title": "bar", "id": 2 }, { "title": "baz", "id": 3 }]; $scope.selected = [];