This is the way I've been doing this sort of stuff. Angular tends to favor declarative manipulation of the dom rather than a imperative one(at least that's the way I've been playing with it).
The markup
<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>
And in the controller
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;
};
EDIT: getSelectedClass()
expects the entire entity but it was being called with the id of the entity only, which is now corrected