4

I'm building a CRUD data management project using Angular and the dirPagination directive and need to have a "select all" checkbox that selects all rows that are visible /without/ using jQuery.

I started with this - note - I am climbing the Angular learning curve and am aware that some/all of this may not be "the Angular way" but I also don't want to start fiddling (no pun) with the guts of dirPagination, ergo the dirPagination directive:

 <tr dir-paginate-start="item in items|filter:filterFunction()|orderBy:sortPredicate:reverse| itemsPerPage: rowsPerPage">

and the individual row-checkbox

<input type="checkbox" class="rowSelector" ng-model="item.isSelected"  ng-change="rowSelect($index, $event)"/> status: {{item.isSelected}}

and the related model elements:

$scope.items = [] //subsequently filled
$scope.rowsPerPage = 5;
$scope.rowSelect = function (ix, $event) {
           var checked = (typeof $event == 'undefined') ? false : true;
           if (!checked) { $scope.masterCheck = false; }
           var rpp = $scope.rowsPerPage;
           var p = $scope.__default__currentPage;  //dirPagination's current page
           var start = ((Math.max(0, p - 1) * rpp));
           $scope.items[start + ix].isSelected = checked;
       };

that works as expected. Check/uncheck a row and the {{item.isSelected}} value is updated in the model and is displayed beside the checkbox.

Then I added this /outside/ of the dirPagination repeat block:

<input type="checkbox" id="masterCheckbox" ng-model="masterCheck" ng-click="checkAll()" />

and the related function in the model:

 $scope.masterCheck = false;
 $scope.checkAll = function () {
           var rpp = $scope.rowsPerPage;
           var p = $scope.__default__currentPage;          //dirPagination's current page
           var start = ((Math.max(0, p - 1) * rpp));
           var checked = $scope.masterCheck == true;
           var rows = document.getElementsByClassName("rowSelector");
           for (var ix = 0; ix < rows.length; ix++) {
               rows[ix].checked = checked;
               $scope.items[start + ix].isSelected = checked;
           }
       }

however in the checkAll() function checking/unchecking the individual rows isn't reflected in the {{item.isSelected}} display of each row.

Explicitly setting the individual item with

$scope.items[start + ix].isSelected = checked;

seems to set the 'isSelected' property of that item within the scope of the checkAll function but the row display does not change.

Clearly I have something wrong perhaps misunderstanding a Scope issue but at this point I'm stumped.

Any help greatly appreciated :-)

Serexx
  • 1,232
  • 1
  • 15
  • 32
  • I have the for this problem in my previous post [enter link description here](http://stackoverflow.com/questions/33341103/i-want-to-delete-multiple-rows-selected-from-table-dom-is-changing-but-it-is-de) – Prathap Kudupu Nov 25 '15 at 22:22

2 Answers2

3

The light dawned, finally.

checkAll() as written tried to access each row by calculating its position using dir-paginate's __default__currentPage and Angular's row $index.

Of course that doesn't work because the items[] collection held by dir-paginate has been subjected to filtering and sorting, so while items[] do get checked (item.isSelected = true) the selected items/rows were living on non-visible pages. i.e. - we were selecting the wrong indexes.

One solution is comprised of the following -

The master checkbox

<input type="checkbox" id="masterCheckbox" ng-model="masterCheck" ng-click="checkAll()" />

The row checkbox (note function calls)

<input type="checkbox" class="rowSelector" value="{{sourceIndex('senId',item.senId)}}" ng-model="item.isSelected" ng-click="rowSelect(this)" />

the dir-paginate directive controls tag

 <dir-pagination-controls on-page-change="onPageChange(newPageNumber)" max-size="15" direction-links="true" boundary-links="true" pagination-id="" template-url=""></dir-pagination-controls>

and the related $scope values and functions:

       $scope.items = [];
       $scope.masterCheck = false;
       $scope.onPageChange = function (newPageNumber) {
           //clear all selections on page change
           //dir-paginate provides this hook
           $scope.masterCheck = false;
           for (var i in $scope.items) {
               $scope.items[i].isSelected = false;
           }
       }

       $scope.rowSelect = function (item) {
           //if one is unchecked have to turn master off
           if (!item.isSelected) $scope.masterCheck = false;
       }

       $scope.sourceIndex = function (keyName, key) {
           //gets the actual items index for the row key
           //see here http://stackoverflow.com/questions/21631127/find-the-array-index-of-an-object-with-a-specific-key-value-in-underscore
           //for the 'getIndexBy' prototype extension
           var ix = $scope.items.getIndexBy(keyName, key);
           return ix;

       }

       $scope.checkAll = function () {
           //only visible rows 
           var boxes = document.getElementsByClassName("rowSelector");
           for (var bix in boxes) {
               var ix = boxes[bix].value;
               $scope.items[ix].isSelected = $scope.masterCheck;
           }
       }

There is probably a better way but while not highly efficient this one works well enough for common folk.

The $scope.sourceIndex() function stuffs the actual source row index into the row checkbox as its value= attribute value.

The checkAll() function then grabs all visible rows by the "rowSelector" class and then iterates through those grabbing the data index from the checkbox value and setting the appropriate item.isSelected.

The $scope.onPageChange is specified in the dir-Paginate controls directive and ensures that when the page changes, all row selections are cleared.

Happy happy.

Serexx
  • 1,232
  • 1
  • 15
  • 32
0

Your variable masterCheck is being set to false in rowSelect() and subsequently in checkAll() you are setting checked to masterCheck which then is used to assign isSelected

This line is wrong:

var checked = $scope.masterCheck == true;

Because you want to flip masterCheck so it should be:

$scope.masterCheck = !$scope.masterCheck;

and then

.isSelected = $scope.masterCheck;

You weren't ever setting $scope.masterCheck to true so it was always false and since your isSelected values depended on it, they were always false. Also, this functions as a checkAll/unCheckAll to make it only check all change to the following:

$scope.masterCheck = !$scope.masterCheck;
var checked = $scope.masterCheck == true;
user3727843
  • 574
  • 1
  • 4
  • 13
  • Thanks but that line simply unchecks the "select all" checkbox if any of the individual rows become unchecked, which is the correct behavior. The issue is that checking the Master checkbox in the first place does not change the individual row status displays. I did try removing it out of curiosity but no joy unfortunately. – Serexx Jul 02 '15 at 18:18
  • No sorry in the line you are looking at var checked reflects the checked status of the masterCheck box *after* it has been clicked. All that line does is determine what status it is now, post click. We then set the status of each row to match that status whatever it is. The row check-marks are being set correctly and are displayed correctly. – Serexx Jul 02 '15 at 18:39