如何响应 AngularJS 指令中复选框上的单击?

我有一个 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>,每一行都可以用它自己的复选框单独选择,或者所有行都可以用位于 <thead>中的主复选框一次选择。非常经典的用户界面。

什么是最好的方法:

  • 选择一行(例如,当选中复选框时,将所选实体的 id 添加到内部数组中,并向包含该实体以反映其所选状态的 <tr>中添加一个 CSS 类) ?
  • 一次选择所有行? (即对 <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函数中?
  • 假设 jQuery 不一定存在(AngularJS 不需要它) ,那么执行 DOM 遍历的最佳方法是什么?没有 jQuery,我很难选择给定复选框的父 <tr>,或者选择模板中的所有复选框。
  • $event传递给 updateSelection()看起来并不是很优雅。难道没有更好的方法来检索刚刚单击的元素的状态(选中/未选中)吗?

谢谢你。

160081 次浏览

我一直都是这么做的。Angular 倾向于支持对 dom 的陈述式操作,而不是命令式操作(至少我一直是这么玩的)。

加价

<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()希望调用整个实体,但是只使用实体的 id 调用它,现在已经更正

利维乌的回答对我非常有帮助。希望这不是一个坏的形式,但我做了一个 小提琴,可以帮助其他人在未来。

我们需要的两个重要部分是:

    $scope.entities = [{
"title": "foo",
"id": 1
}, {
"title": "bar",
"id": 2
}, {
"title": "baz",
"id": 3
}];
$scope.selected = [];

处理复选框时,我更喜欢使用 ngModel < strong > ngChange 指令。NgModel 允许您将复选框的选中/未选中状态绑定到实体上的属性:

<input type="checkbox" ng-model="entity.isChecked">

每当用户选中或取消选中该复选框时,entity.isChecked值也将发生变化。

如果这就是您所需要的,那么您甚至不需要 ngClick 或 ngChange 指令。因为您有“ CheckAll”复选框,所以当有人选中复选框时,显然需要做的不仅仅是设置属性的值。

当使用带有复选框的 ngModel 时,最好使用 ngChange 而不是 ngClick 来处理选中和未选中的事件。NgChange 就是为这种情况而设计的。它使用 模型控制器进行数据绑定(它向 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;
};

类似地,标题中的“复选全部”复选框:

<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>包含实体,以反映其选定的状态?

如果使用 ngModel 方法进行数据绑定,那么您所需要做的就是向 <tr>元素添加 NgClass指令,以便在实体属性发生变化时动态地添加或删除该类:

<tr ng-repeat="entity in model.entities" ng-class="{selected: entity.isChecked}">

看完整的 我是普朗克