Skip to content

Commit

Permalink
fix(selection.js): Allow selection in tables that use grouping (#6556)
Browse files Browse the repository at this point in the history
Modified the GridRow to default the isSelected flag to false

fix #3911, fix #6126, fix #6145, fix #6263, fix #6398
  • Loading branch information
yonatankarimish authored and mportuga committed Feb 1, 2018
1 parent ccdc72c commit f3d2a7f
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 56 deletions.
125 changes: 96 additions & 29 deletions src/features/selection/js/selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,23 @@
service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
}
},
/**
* @ngdoc function
* @name unSelectRowByVisibleIndex
* @methodOf ui.grid.selection.api:PublicApi
* @description Unselect the specified row by visible index (i.e. if you
* specify row 0 you'll get the first visible row unselected). In this context
* visible means of those rows that are theoretically visible (i.e. not filtered),
* rather than rows currently rendered on the screen.
* @param {number} index index within the rowsVisible array
* @param {Event} event object if raised from an event
*/
unSelectRowByVisibleIndex: function (rowNum, evt) {
var row = grid.renderContainers.body.visibleRowCache[rowNum];
if (row !== null && typeof (row) !== 'undefined' && row.isSelected) {
service.toggleRowSelection(grid, row, evt, grid.options.multiSelect, grid.options.noUnselect);
}
},
/**
* @ngdoc function
* @name selectAllRows
Expand Down Expand Up @@ -238,26 +255,32 @@
* @param {Event} event object if raised from an event
*/
selectAllVisibleRows: function (evt) {
if (grid.options.multiSelect === false) {
return;
}

var changedRows = [];
grid.rows.forEach(function (row) {
if (row.visible) {
if (!row.isSelected && row.enableSelection !== false) {
row.setSelected(true);
service.decideRaiseSelectionEvent(grid, row, changedRows, evt);
}
if (grid.options.multiSelect !== false) {
var changedRows = [];
var rowCache = [];
if (grid.treeBase && grid.treeBase.tree) {
rowCache = getAllTreeRows(grid.treeBase.tree);
} else {
if (row.isSelected) {
row.setSelected(false);
service.decideRaiseSelectionEvent(grid, row, changedRows, evt);
rowCache = grid.rows;
}

for (var i = 0; i<rowCache.length; i++) {
var row = rowCache[i];
if (row.visible) {
if (!row.isSelected && row.enableSelection !== false) {
row.setSelected(true);
service.decideRaiseSelectionEvent(grid, row, changedRows, event);
}
} else {
if (row.isSelected) {
row.setSelected(false);
service.decideRaiseSelectionEvent(grid, row, changedRows, event);
}
}
}
});
service.decideRaiseSelectionBatchEvent(grid, changedRows, evt);
grid.selection.selectAll = true;
service.decideRaiseSelectionBatchEvent(grid, changedRows, event);
grid.selection.selectAll = true;
}
},
/**
* @ngdoc function
Expand Down Expand Up @@ -493,6 +516,8 @@
grid.selection.selectAll = grid.rows.length === selectedRows.length;

grid.api.selection.raise.rowSelectionChanged(row, evt);

toggleParentHeaders(grid, row, event, multiSelect, noUnselect);
}
},
/**
Expand Down Expand Up @@ -540,9 +565,20 @@
* @param {Grid} grid grid object
*/
getSelectedRows: function (grid) {
return grid.rows.filter(function (row) {
return row.isSelected;
});
var rows;
if (grid.treeBase && grid.treeBase.tree) {
rows = getAllTreeRows(grid.treeBase.tree);
} else {
rows = grid.rows;
}

var selectedRows = [];
for (var i = 0; i<rows.length; i++) {
if (rows[i].isSelected) {
selectedRows.push(rows[i]);
}
}
return selectedRows;
},

/**
Expand Down Expand Up @@ -605,6 +641,30 @@

return service;

function toggleParentHeaders(grid, row, event, multiSelect, noUnselect){
if (row.treeNode &&row.treeNode.parentRow) {
var parentRow = row.treeNode.parentRow;
var siblingSelectedStatus = [];
for (var i = 0; i < parentRow.treeNode.children.length; i++) {
siblingSelectedStatus.push(parentRow.treeNode.children[i].row.isSelected);
}
var allSiblingsSelected = siblingSelectedStatus.indexOf(false) === -1;

if (parentRow.isSelected !== allSiblingsSelected) {
service.toggleRowSelection(grid, parentRow, event, multiSelect, noUnselect);
}
}
}

function getAllTreeRows(rowTree){
var selectedRows = [];
for (var i = 0; i<rowTree.length; i++) {
var node = rowTree[i];
selectedRows.push(node.row);
selectedRows = selectedRows.concat(getAllTreeRows(node.children));
}
return selectedRows;
}
}]);

/**
Expand Down Expand Up @@ -726,18 +786,25 @@
function selectButtonClick(row, evt) {
evt.stopPropagation();

if (evt.shiftKey) {
uiGridSelectionService.shiftSelect(self, row, evt, self.options.multiSelect);
}
else if (evt.ctrlKey || evt.metaKey) {
uiGridSelectionService.toggleRowSelection(self, row, evt, self.options.multiSelect, self.options.noUnselect);
}
else if (row.groupHeader) {
if (row.groupHeader) {
selectByKeyState(row, evt);
var selectionState = row.isSelected;
for (var i = 0; i < row.treeNode.children.length; i++) {
uiGridSelectionService.toggleRowSelection(self, row.treeNode.children[i].row, evt, self.options.multiSelect, self.options.noUnselect);
if (row.treeNode.children[i].row.isSelected !== selectionState) {
selectButtonClick(row.treeNode.children[i].row, evt);
}
}
}else {
selectByKeyState(row, evt);
}
else {
}

function selectByKeyState(row, evt){
if (evt.shiftKey) {
uiGridSelectionService.shiftSelect(self, row, evt, self.options.multiSelect);
} else if (evt.ctrlKey || evt.metaKey) {
uiGridSelectionService.toggleRowSelection(self, row, evt, self.options.multiSelect, self.options.noUnselect);
} else {
uiGridSelectionService.toggleRowSelection(self, row, evt, (self.options.multiSelect && !self.options.modifierKeysToMultiSelect), self.options.noUnselect);
}
}
Expand Down
18 changes: 9 additions & 9 deletions src/features/selection/test/uiGridSelectionService.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('ui.grid.selection uiGridSelectionService', function () {
it('should not toggle selected with enableSelection: false', function () {
grid.rows[0].enableSelection = false;
uiGridSelectionService.toggleRowSelection(grid, grid.rows[0], null, true);
expect(grid.rows[0].isSelected).toBe(undefined);
expect(grid.rows[0].isSelected).toBe(false);
});

it('should toggle selected with noUnselect', function () {
Expand Down Expand Up @@ -124,7 +124,7 @@ describe('ui.grid.selection uiGridSelectionService', function () {
uiGridSelectionService.shiftSelect(grid, grid.rows[5], null, true);
expect(grid.rows[2].isSelected).toBe(true);
expect(grid.rows[3].isSelected).toBe(true);
expect(grid.rows[4].isSelected).toBe(undefined);
expect(grid.rows[4].isSelected).toBe(false);
expect(grid.rows[5].isSelected).toBe(true);
});

Expand Down Expand Up @@ -173,21 +173,21 @@ describe('ui.grid.selection uiGridSelectionService', function () {
expect(grid.rows[4].isSelected).toBe(false);
});
});

describe('setSelected function', function() {
it('select row and check the selected count is correct', function() {

expect(grid.selection.selectedCount).toBe(0);

grid.rows[0].setSelected(true);
expect(grid.rows[0].isSelected).toBe(true);
expect(grid.selection.selectedCount).toBe(1);

// the second setSelected(true) should have no effect
grid.rows[0].setSelected(true);
expect(grid.rows[0].isSelected).toBe(true);
expect(grid.selection.selectedCount).toBe(1);

grid.rows[0].setSelected(false);
expect(grid.rows[0].isSelected).toBe(false);
expect(grid.selection.selectedCount).toBe(0);
Expand Down Expand Up @@ -265,7 +265,7 @@ describe('ui.grid.selection uiGridSelectionService', function () {
expect(grid.rows[4].isSelected).toBe(true);
expect(grid.rows[6].isSelected).toBe(false);
expect(grid.rows[7].isSelected).toBe(true);
expect(grid.rows[8].isSelected).toBe(undefined);
expect(grid.rows[8].isSelected).toBe(false);
expect(grid.rows[9].isSelected).toBe(true);
expect(grid.selection.selectAll).toBe(true);
expect(grid.selection.selectedCount).toBe(8);
Expand All @@ -285,7 +285,7 @@ describe('ui.grid.selection uiGridSelectionService', function () {

grid.rows[3].enableSelection = false;
grid.api.selection.selectRowByVisibleIndex(2);
expect(grid.rows[3].isSelected).toBe(undefined);
expect(grid.rows[3].isSelected).toBe(false);
});
});

Expand Down
45 changes: 27 additions & 18 deletions src/js/core/factories/GridRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ angular.module('ui.grid')
// Default to true
this.visible = true;

/**
* @ngdoc object
* @name isSelected
* @propertyOf ui.grid.class:GridRow
* @description Marks if the row has been selected
*/
// Default to false
this.isSelected = false;


this.$$height = grid.options.rowHeight;

Expand Down Expand Up @@ -100,52 +109,52 @@ angular.module('ui.grid')
}
return gridUtil.preEval(base + '.' + col.field);
};


/**
* @ngdoc function
* @name setRowInvisible
* @methodOf ui.grid.class:GridRow
* @description Sets an override on the row that forces it to always
* be invisible. Emits the rowsVisibleChanged event if it changed the row visibility.
*
*
* This method can be called from the api, passing in the gridRow we want
* altered. It should really work by calling gridRow.setRowInvisible, but that's
* not the way I coded it, and too late to change now. Changed to just call
* the internal function row.setThisRowInvisible().
*
*
* @param {GridRow} row the row we want to set to invisible
*
*
*/
GridRow.prototype.setRowInvisible = function ( row ) {
if (row && row.setThisRowInvisible){
row.setThisRowInvisible( 'user' );
}
};


/**
* @ngdoc function
* @name clearRowInvisible
* @methodOf ui.grid.class:GridRow
* @description Clears an override on the row that forces it to always
* be invisible. Emits the rowsVisibleChanged event if it changed the row visibility.
*
*
* This method can be called from the api, passing in the gridRow we want
* altered. It should really work by calling gridRow.clearRowInvisible, but that's
* not the way I coded it, and too late to change now. Changed to just call
* the internal function row.clearThisRowInvisible().
*
*
* @param {GridRow} row the row we want to clear the invisible flag
*
*
*/
GridRow.prototype.clearRowInvisible = function ( row ) {
if (row && row.clearThisRowInvisible){
row.clearThisRowInvisible( 'user' );
}
};


/**
* @ngdoc function
* @name setThisRowInvisible
Expand All @@ -170,10 +179,10 @@ angular.module('ui.grid')
* @ngdoc function
* @name clearRowInvisible
* @methodOf ui.grid.class:GridRow
* @description Clears any override on the row visibility, returning it
* @description Clears any override on the row visibility, returning it
* to normal visibility calculations. Emits the rowsVisibleChanged
* event
*
*
* @param {string} reason the reason (usually the module) for the row to be invisible.
* E.g. grouping, user, filter
* @param {boolean} fromRowsProcessor whether we were called from a rowsProcessor, passed through to evaluateRowVisibility
Expand All @@ -190,9 +199,9 @@ angular.module('ui.grid')
* @ngdoc function
* @name evaluateRowVisibility
* @methodOf ui.grid.class:GridRow
* @description Determines whether the row should be visible based on invisibleReason,
* @description Determines whether the row should be visible based on invisibleReason,
* and if it changes the row visibility, then emits the rowsVisibleChanged event.
*
*
* Queues a grid refresh, but doesn't call it directly to avoid hitting lots of grid refreshes.
* @param {boolean} fromRowProcessor if true, then it won't raise events or queue the refresh, the
* row processor does that already
Expand All @@ -206,7 +215,7 @@ angular.module('ui.grid')
}
});
}

if ( typeof(this.visible) === 'undefined' || this.visible !== newVisibility ){
this.visible = newVisibility;
if ( !fromRowProcessor ){
Expand All @@ -215,7 +224,7 @@ angular.module('ui.grid')
}
}
};


return GridRow;
}]);
Expand Down

0 comments on commit f3d2a7f

Please sign in to comment.