Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
16
rated 0 times [  20] [ 4]  / answers: 1 / hits: 160362  / 12 Years ago, wed, august 8, 2012, 12:00:00

I have an AngularJS directive that renders a collection of entities in the following template:



<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>


As you can see, it's a <table> where each row can be selected individually with its own checkbox, or all rows can be selected at once with a master checkbox located in the <thead>. Pretty classic UI.



What is the best way to:




  • Select a single row (i.e. when the checkbox is checked, add the id of the selected entity to an internal array, and add a CSS class to the <tr> containing the entity to reflect its selected state)?

  • Select all rows at once? (i.e. do the previously described actions for all rows in the <table>)



My current implementation is to add a custom controller to my directive:



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??
};
}


More specifically, I wonder:




  • Does the code above belong in a controller or should it go in a link function?

  • Given that jQuery is not necessarily present (AngularJS doesn't require it), what's the best way to do DOM traversal? Without jQuery, I'm having a hard time just selecting the parent <tr> of a given checkbox, or selecting all checkboxes in the template.

  • Passing $event to updateSelection() doesn't seem very elegant. Isn't there a better way to retrieve the state (checked/unchecked) of an element that was just clicked?



Thank you.


More From » angularjs

 Answers
40

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


[#83752] Tuesday, August 7, 2012, 12 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
lucianod

Total Points: 667
Total Questions: 106
Total Answers: 92

Location: Jordan
Member since Thu, Aug 5, 2021
3 Years ago
lucianod questions
;