From 14edc9165a6df6f2503e53bc42bbefb3fcd69ccf Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Sat, 6 Jan 2024 12:25:08 +0200 Subject: [PATCH 01/13] fix(grid): Correct shift-click selection in grouped IgxGrid #13757 --- package-lock.json | 45 +++++++++++- package.json | 4 +- .../lib/grids/selection/selection.service.ts | 70 +++++++++++++++---- 3 files changed, 104 insertions(+), 15 deletions(-) diff --git a/package-lock.json b/package-lock.json index df2a1294e19..145ddc316a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,11 +25,12 @@ "express": "^4.18.2", "fflate": "^0.8.1", "hammerjs": "^2.0.8", + "igniteui-angular": "^17.0.8", "igniteui-theming": "^4.0.1", "igniteui-trial-watermark": "^3.0.2", "lodash-es": "^4.17.21", "rxjs": "^6.6.7", - "tslib": "^2.3.0", + "tslib": "^2.6.2", "uuid": "^9.0.0", "zone.js": "~0.14.2" }, @@ -75,6 +76,7 @@ "karma-chrome-launcher": "~3.2.0", "karma-coverage": "^2.0.3", "karma-jasmine": "~5.1.0", + "karma-jasmine-spec-tags": "^2.0.0", "karma-junit-reporter": "^2.0.1", "karma-parallel": "^0.3.1", "karma-spec-reporter": "^0.0.36", @@ -12827,6 +12829,36 @@ "integrity": "sha512-hC5pinvq0ziDRZmrGRuXY8rJWjWv45Vj/utXFaiX5sAt+hifW7xFMTQPu679187EMe3HOHhaZc3K7vhy/8iPNA==", "dev": true }, + "node_modules/igniteui-angular": { + "version": "17.0.8", + "resolved": "https://registry.npmjs.org/igniteui-angular/-/igniteui-angular-17.0.8.tgz", + "integrity": "sha512-OgUMyhCRL7uO/9jHHepZxpHk4Iy4hr3Ju/Z3AQUPNuKQpN3HioPEhs4DlLaVN/VHQmRgYGxHNMNHSTVncw05xg==", + "dependencies": { + "@igniteui/material-icons-extended": "^3.0.0", + "@types/hammerjs": "^2.0.40", + "fflate": "^0.8.1", + "hammerjs": "^2.0.8", + "igniteui-theming": "^3.3.3", + "igniteui-trial-watermark": "^3.0.2", + "lodash-es": "^4.17.21", + "tslib": "^2.3.0", + "uuid": "^9.0.0" + }, + "peerDependencies": { + "@angular/animations": "^17.0.0", + "@angular/common": "^17.0.0", + "@angular/core": "^17.0.0", + "@angular/forms": "^17.0.0" + } + }, + "node_modules/igniteui-angular/node_modules/igniteui-theming": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/igniteui-theming/-/igniteui-theming-3.3.3.tgz", + "integrity": "sha512-f15sUvOvgzDuQjEdVy2onX4DVjYwa3g3MdtSspudf8WurlvLb54TK+bC/sEOfhfrTnaRMC/laGmRWfjD13ebkw==", + "peerDependencies": { + "sass": "^1.58.1" + } + }, "node_modules/igniteui-sassdoc-theme": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/igniteui-sassdoc-theme/-/igniteui-sassdoc-theme-1.2.2.tgz", @@ -14204,6 +14236,17 @@ "karma": "^6.0.0" } }, + "node_modules/karma-jasmine-spec-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-spec-tags/-/karma-jasmine-spec-tags-2.0.0.tgz", + "integrity": "sha512-ckTZvS+w9LyYQtI/LY6nNS6oiuQM7bSRzJgLBwde5Ivr6k5uQ1y58HD77YQH9+rWIj048LXBpXk2VY3ws9hE2A==", + "dev": true, + "peerDependencies": { + "jasmine": ">=4 || >=5", + "karma": ">=6.0.4", + "karma-jasmine": "*" + } + }, "node_modules/karma-jasmine/node_modules/jasmine-core": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.0.tgz", diff --git a/package.json b/package.json index dd598f9e678..fe212f414e2 100644 --- a/package.json +++ b/package.json @@ -72,11 +72,12 @@ "express": "^4.18.2", "fflate": "^0.8.1", "hammerjs": "^2.0.8", + "igniteui-angular": "^17.0.8", "igniteui-theming": "^4.0.1", "igniteui-trial-watermark": "^3.0.2", "lodash-es": "^4.17.21", "rxjs": "^6.6.7", - "tslib": "^2.3.0", + "tslib": "^2.6.2", "uuid": "^9.0.0", "zone.js": "~0.14.2" }, @@ -122,6 +123,7 @@ "karma-chrome-launcher": "~3.2.0", "karma-coverage": "^2.0.3", "karma-jasmine": "~5.1.0", + "karma-jasmine-spec-tags": "^2.0.0", "karma-junit-reporter": "^2.0.1", "karma-parallel": "^0.3.1", "karma-spec-reporter": "^0.0.36", diff --git a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts index d9201d2906d..96958caf392 100644 --- a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts +++ b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts @@ -417,7 +417,7 @@ export class IgxGridSelectionService { public getSelectedRows(): Array { return this.rowSelection.size ? Array.from(this.rowSelection.keys()) : []; } - + /** Returns array of the rows in indeterminate state. */ public getIndeterminateRows(): Array { return this.indeterminateRows.size ? Array.from(this.indeterminateRows.keys()) : []; @@ -586,24 +586,36 @@ export class IgxGridSelectionService { return this.indeterminateRows.size > 0 && this.indeterminateRows.has(rowID); } - /** Select range from last selected row to the current specified row. */ + /** Select range from last selected row to the current specified row. */ public selectMultipleRows(rowID, rowData, event?): void { this.clearHeaderCBState(); if (!this.rowSelection.size || this.isRowDeleted(rowID)) { this.selectRowById(rowID); return; } - const gridData = this.allData; - const lastRowID = this.getSelectedRows()[this.rowSelection.size - 1]; - const currIndex = gridData.indexOf(this.getRowDataById(lastRowID)); - const newIndex = gridData.indexOf(rowData); - const rows = gridData.slice(Math.min(currIndex, newIndex), Math.max(currIndex, newIndex) + 1); - const currSelection = this.getSelectedRowsData(); - const added = rows.filter(r => !this.isRowSelected(this.getRecordKey(r))); - const newSelection = currSelection.concat(added); - this.emitRowSelectionEvent(newSelection, added, [], event, currSelection); - } - + const gridData = this.allData; + const lastSelectedRowID = this.getSelectedRows()[this.rowSelection.size - 1]; + const currentRowIndex = gridData.findIndex(row => this.getRecordKey(row) === rowID); + const lastSelectedRowIndex = gridData.findIndex(row => this.getRecordKey(row) === lastSelectedRowID); + + const currentGroup = this.getGroup(rowData); + const lastSelectedGroup = this.getGroup(this.getRowDataById(lastSelectedRowID)); + + if (!this.areGroupsEqual(currentGroup, lastSelectedGroup)) { + this.selectRowById(rowID, false, event); + return; + } + + const rangeStart = Math.min(currentRowIndex, lastSelectedRowIndex); + const rangeEnd = Math.max(currentRowIndex, lastSelectedRowIndex) + 1; + const rowsToSelect = gridData.slice(rangeStart, rangeEnd).filter(row => + this.areGroupsEqual(this.getGroup(row), currentGroup)); + + const newSelection = [...this.getSelectedRowsData(), ...rowsToSelect]; + const addedRows = rowsToSelect.filter(row => !this.isRowSelected(this.getRecordKey(row))); + this.emitRowSelectionEvent(newSelection, addedRows, [], event, this.getSelectedRowsData()); + } + public areAllRowSelected(newSelection?): boolean { if (!this.grid.data && !newSelection) { return false; @@ -674,6 +686,38 @@ export class IgxGridSelectionService { return this.grid.primaryKey && data.length ? data.map(rec => rec[this.grid.primaryKey]) : data; } + public getGroup(rowData: any): any { + if (this.grid.groupingExpressions.length === 0) { + return null; + } + + const groupValues = {}; + + for (let expr of this.grid.groupingExpressions) { + if (rowData.hasOwnProperty(expr.fieldName)) { + groupValues[expr.fieldName] = rowData[expr.fieldName]; + } else { + return null; + } + } + + return groupValues; + } + + private areGroupsEqual(group1, group2): boolean { + for (const prop in group1) { + if (group1.hasOwnProperty(prop) && group2.hasOwnProperty(prop)) { + if (group1[prop] !== group2[prop]) { + return false; + } + } else { + return false; + } + } + return true; + } + + public getRecordKey(record) { return this.grid.primaryKey ? record[this.grid.primaryKey] : record; } From b397b717fe76ab357c1f1c8db7ebaa96c06080b0 Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Wed, 10 Jan 2024 17:33:38 +0200 Subject: [PATCH 02/13] fix(grid): Added conditional checks and enchanced comparison function --- .../lib/grids/selection/selection.service.ts | 71 ++++++++++++++----- 1 file changed, 52 insertions(+), 19 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts index 96958caf392..5955fc2ef1a 100644 --- a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts +++ b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts @@ -593,26 +593,41 @@ export class IgxGridSelectionService { this.selectRowById(rowID); return; } - const gridData = this.allData; + + const isGrouped = this.grid.groupingExpressions.length > 0; + const dataView = this.grid.dataView; + + let currentRowIndex, lastSelectedRowIndex; + let rowsToSelect = []; + const lastSelectedRowID = this.getSelectedRows()[this.rowSelection.size - 1]; - const currentRowIndex = gridData.findIndex(row => this.getRecordKey(row) === rowID); - const lastSelectedRowIndex = gridData.findIndex(row => this.getRecordKey(row) === lastSelectedRowID); + const lastSelectedRowData = this.getRowDataById(lastSelectedRowID); - const currentGroup = this.getGroup(rowData); - const lastSelectedGroup = this.getGroup(this.getRowDataById(lastSelectedRowID)); + if (isGrouped) { + const currentGroup = this.getGroup(rowData); + const lastSelectedGroup = this.getGroup(lastSelectedRowData); - if (!this.areGroupsEqual(currentGroup, lastSelectedGroup)) { - this.selectRowById(rowID, false, event); - return; + // enhanced group comparison to handle hierarchical data + if (!this.deepCompareGroups(currentGroup, lastSelectedGroup)) { + this.selectRowById(rowID, false, event); + return; + } + + rowsToSelect = dataView.filter(row => this.deepCompareGroups(this.getGroup(row), currentGroup)); + currentRowIndex = rowsToSelect.findIndex(row => this.getRecordKey(row) === rowID); + lastSelectedRowIndex = rowsToSelect.findIndex(row => this.getRecordKey(row) === this.getRecordKey(lastSelectedRowData)); + } else { + currentRowIndex = dataView.findIndex(row => this.getRecordKey(row) === rowID); + lastSelectedRowIndex = dataView.findIndex(row => this.getRecordKey(row) === this.getRecordKey(lastSelectedRowData)); + rowsToSelect = dataView; } const rangeStart = Math.min(currentRowIndex, lastSelectedRowIndex); const rangeEnd = Math.max(currentRowIndex, lastSelectedRowIndex) + 1; - const rowsToSelect = gridData.slice(rangeStart, rangeEnd).filter(row => - this.areGroupsEqual(this.getGroup(row), currentGroup)); + const selectedRows = rowsToSelect.slice(rangeStart, rangeEnd); - const newSelection = [...this.getSelectedRowsData(), ...rowsToSelect]; - const addedRows = rowsToSelect.filter(row => !this.isRowSelected(this.getRecordKey(row))); + const newSelection = [...this.getSelectedRowsData(), ...selectedRows]; + const addedRows = selectedRows.filter(row => !this.isRowSelected(this.getRecordKey(row))); this.emitRowSelectionEvent(newSelection, addedRows, [], event, this.getSelectedRowsData()); } @@ -704,13 +719,31 @@ export class IgxGridSelectionService { return groupValues; } - private areGroupsEqual(group1, group2): boolean { - for (const prop in group1) { - if (group1.hasOwnProperty(prop) && group2.hasOwnProperty(prop)) { - if (group1[prop] !== group2[prop]) { - return false; - } - } else { + private deepCompareGroups(group1, group2): boolean { + if (group1 === group2) { + return true; + } + + if (typeof group1 !== 'object' || typeof group2 !== 'object' || group1 == null || group2 == null) { + return false; + } + + const keys1 = Object.keys(group1); + const keys2 = Object.keys(group2); + + if (keys1.length !== keys2.length) { + return false; + } + + for (const key of keys1) { + const val1 = group1[key]; + const val2 = group2[key]; + + const areObjects = (val1 != null && typeof val1 === 'object') && (val2 != null && typeof val2 === 'object'); + if ( + areObjects && !this.deepCompareGroups(val1, val2) || + !areObjects && val1 !== val2 + ) { return false; } } From d696bb9d5393a3c1559181950eed613a8f4b5ad4 Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Thu, 11 Jan 2024 15:26:45 +0200 Subject: [PATCH 03/13] fix(grid): Taking into account duplicate rows --- .../src/lib/grids/selection/selection.service.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts index 5955fc2ef1a..6bcad1a7de9 100644 --- a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts +++ b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts @@ -607,7 +607,6 @@ export class IgxGridSelectionService { const currentGroup = this.getGroup(rowData); const lastSelectedGroup = this.getGroup(lastSelectedRowData); - // enhanced group comparison to handle hierarchical data if (!this.deepCompareGroups(currentGroup, lastSelectedGroup)) { this.selectRowById(rowID, false, event); return; @@ -624,11 +623,13 @@ export class IgxGridSelectionService { const rangeStart = Math.min(currentRowIndex, lastSelectedRowIndex); const rangeEnd = Math.max(currentRowIndex, lastSelectedRowIndex) + 1; - const selectedRows = rowsToSelect.slice(rangeStart, rangeEnd); + const rangeSelection = rowsToSelect.slice(rangeStart, rangeEnd); - const newSelection = [...this.getSelectedRowsData(), ...selectedRows]; - const addedRows = selectedRows.filter(row => !this.isRowSelected(this.getRecordKey(row))); - this.emitRowSelectionEvent(newSelection, addedRows, [], event, this.getSelectedRowsData()); + let existingSelectionSet = new Set(this.getSelectedRowsData().map(r => this.getRecordKey(r))); + const newSelection = rangeSelection.filter(row => !existingSelectionSet.has(this.getRecordKey(row))); + + const addedRows = newSelection.filter(row => !this.isRowSelected(this.getRecordKey(row))); + this.emitRowSelectionEvent([...this.getSelectedRowsData(), ...newSelection], addedRows, [], event, this.getSelectedRowsData()); } public areAllRowSelected(newSelection?): boolean { From f608be89e50e42118ca4ffd039d69a76fcb5a759 Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Fri, 12 Jan 2024 11:27:17 +0200 Subject: [PATCH 04/13] fix(grid): Fixed indexing on non-grouped selection --- .../src/lib/grids/grid/grid-row-selection.spec.ts | 5 +++++ .../src/lib/grids/selection/selection.service.ts | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts index ad3b8c18631..d647be876d1 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts @@ -1639,12 +1639,17 @@ describe('IgxGrid - Row Selection #grid', () => { grid.notifyChanges(); fix.detectChanges(); + console.log('Selected rows after first selection:', grid.selectedRows); + GridSelectionFunctions.verifyHeaderRowCheckboxState(fix, false, true); GridSelectionFunctions.verifyRowSelected(firstRow); grid.paginator.nextPage(); fix.detectChanges(); + console.log('Current page index after next page:', grid.paginator.page); + console.log('Selected rows after page change:', grid.selectedRows); + GridSelectionFunctions.verifyHeaderRowCheckboxState(fix, false, true); GridSelectionFunctions.verifyRowsArraySelected(grid.rowList.toArray(), false); diff --git a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts index 6bcad1a7de9..32ac27b7ef1 100644 --- a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts +++ b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts @@ -44,6 +44,7 @@ export class IgxGridSelectionService { private allRowsSelected: boolean; private _lastSelectedNode: ISelectionNode; + public lastSelectedRowIndex: number = -1; private _ranges: Set = new Set(); private _selectionRange: Range; @@ -626,10 +627,19 @@ export class IgxGridSelectionService { const rangeSelection = rowsToSelect.slice(rangeStart, rangeEnd); let existingSelectionSet = new Set(this.getSelectedRowsData().map(r => this.getRecordKey(r))); - const newSelection = rangeSelection.filter(row => !existingSelectionSet.has(this.getRecordKey(row))); + // updating the existing selection set directly + rangeSelection.forEach(row => { + const rowKey = this.getRecordKey(row); + if (!existingSelectionSet.has(rowKey)) { + existingSelectionSet.add(rowKey); + } + }); + + const newSelection = Array.from(existingSelectionSet).map(id => this.getRowDataById(id)); const addedRows = newSelection.filter(row => !this.isRowSelected(this.getRecordKey(row))); - this.emitRowSelectionEvent([...this.getSelectedRowsData(), ...newSelection], addedRows, [], event, this.getSelectedRowsData()); + + this.emitRowSelectionEvent(newSelection, addedRows, [], event, this.getSelectedRowsData()); } public areAllRowSelected(newSelection?): boolean { From 98c7daeb7c64850cc62b34934750433efad81f81 Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Mon, 15 Jan 2024 11:29:19 +0200 Subject: [PATCH 05/13] fix(grid): Returned previous code and made a slight change --- .../lib/grids/selection/selection.service.ts | 107 ++---------------- 1 file changed, 11 insertions(+), 96 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts index 32ac27b7ef1..0cef33c1b32 100644 --- a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts +++ b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts @@ -594,52 +594,15 @@ export class IgxGridSelectionService { this.selectRowById(rowID); return; } - - const isGrouped = this.grid.groupingExpressions.length > 0; - const dataView = this.grid.dataView; - - let currentRowIndex, lastSelectedRowIndex; - let rowsToSelect = []; - - const lastSelectedRowID = this.getSelectedRows()[this.rowSelection.size - 1]; - const lastSelectedRowData = this.getRowDataById(lastSelectedRowID); - - if (isGrouped) { - const currentGroup = this.getGroup(rowData); - const lastSelectedGroup = this.getGroup(lastSelectedRowData); - - if (!this.deepCompareGroups(currentGroup, lastSelectedGroup)) { - this.selectRowById(rowID, false, event); - return; - } - - rowsToSelect = dataView.filter(row => this.deepCompareGroups(this.getGroup(row), currentGroup)); - currentRowIndex = rowsToSelect.findIndex(row => this.getRecordKey(row) === rowID); - lastSelectedRowIndex = rowsToSelect.findIndex(row => this.getRecordKey(row) === this.getRecordKey(lastSelectedRowData)); - } else { - currentRowIndex = dataView.findIndex(row => this.getRecordKey(row) === rowID); - lastSelectedRowIndex = dataView.findIndex(row => this.getRecordKey(row) === this.getRecordKey(lastSelectedRowData)); - rowsToSelect = dataView; - } - - const rangeStart = Math.min(currentRowIndex, lastSelectedRowIndex); - const rangeEnd = Math.max(currentRowIndex, lastSelectedRowIndex) + 1; - const rangeSelection = rowsToSelect.slice(rangeStart, rangeEnd); - - let existingSelectionSet = new Set(this.getSelectedRowsData().map(r => this.getRecordKey(r))); - - // updating the existing selection set directly - rangeSelection.forEach(row => { - const rowKey = this.getRecordKey(row); - if (!existingSelectionSet.has(rowKey)) { - existingSelectionSet.add(rowKey); - } - }); - - const newSelection = Array.from(existingSelectionSet).map(id => this.getRowDataById(id)); - const addedRows = newSelection.filter(row => !this.isRowSelected(this.getRecordKey(row))); - - this.emitRowSelectionEvent(newSelection, addedRows, [], event, this.getSelectedRowsData()); + const gridData = this.allData; + const lastRowID = this.getSelectedRows()[this.rowSelection.size - 1]; + const currIndex = gridData.indexOf(this.getRowDataById(lastRowID)); + const newIndex = gridData.indexOf(rowData); + const rows = gridData.slice(Math.min(currIndex, newIndex), Math.max(currIndex, newIndex) + 1); + const currSelection = this.getSelectedRowsData(); + const added = rows.filter(r => !this.isRowSelected(this.getRecordKey(r))); + const newSelection = currSelection.concat(added); + this.emitRowSelectionEvent(newSelection, added, [], event, currSelection); } public areAllRowSelected(newSelection?): boolean { @@ -712,55 +675,7 @@ export class IgxGridSelectionService { return this.grid.primaryKey && data.length ? data.map(rec => rec[this.grid.primaryKey]) : data; } - public getGroup(rowData: any): any { - if (this.grid.groupingExpressions.length === 0) { - return null; - } - - const groupValues = {}; - - for (let expr of this.grid.groupingExpressions) { - if (rowData.hasOwnProperty(expr.fieldName)) { - groupValues[expr.fieldName] = rowData[expr.fieldName]; - } else { - return null; - } - } - - return groupValues; - } - - private deepCompareGroups(group1, group2): boolean { - if (group1 === group2) { - return true; - } - - if (typeof group1 !== 'object' || typeof group2 !== 'object' || group1 == null || group2 == null) { - return false; - } - - const keys1 = Object.keys(group1); - const keys2 = Object.keys(group2); - - if (keys1.length !== keys2.length) { - return false; - } - - for (const key of keys1) { - const val1 = group1[key]; - const val2 = group2[key]; - - const areObjects = (val1 != null && typeof val1 === 'object') && (val2 != null && typeof val2 === 'object'); - if ( - areObjects && !this.deepCompareGroups(val1, val2) || - !areObjects && val1 !== val2 - ) { - return false; - } - } - return true; - } - + public getRecordKey(record) { return this.grid.primaryKey ? record[this.grid.primaryKey] : record; @@ -777,7 +692,7 @@ export class IgxGridSelectionService { /** Returns all data in the grid, with applied filtering and sorting and without deleted rows. */ public get allData(): Array { let allData; - if (this.isFilteringApplied() || this.grid.sortingExpressions.length) { + if (this.isFilteringApplied() || this.grid.sortingExpressions.length || this.grid.groupingExpressions?.length) { allData = this.grid.pinnedRecordsCount ? this.grid._filteredSortedUnpinnedData : this.grid.filteredSortedData; } else { allData = this.grid.gridAPI.get_all_data(true); From 2bedbf1ddcb23e370ba29c5714bc7a9f4930a6dd Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Tue, 16 Jan 2024 10:04:20 +0200 Subject: [PATCH 06/13] fix(grid): Formated and cleared code --- package.json | 3 +-- .../src/lib/grids/grid/grid-row-selection.spec.ts | 7 +------ .../src/lib/grids/selection/selection.service.ts | 8 ++------ 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index cd23b332f11..cb7b62e310d 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ "igniteui-trial-watermark": "^3.0.2", "lodash-es": "^4.17.21", "rxjs": "^6.6.7", - "tslib": "^2.6.2", + "tslib": "^2.3.0", "uuid": "^9.0.0", "zone.js": "~0.14.2" }, @@ -123,7 +123,6 @@ "karma-chrome-launcher": "~3.2.0", "karma-coverage": "^2.0.3", "karma-jasmine": "~5.1.0", - "karma-jasmine-spec-tags": "^2.0.0", "karma-junit-reporter": "^2.0.1", "karma-parallel": "^0.3.1", "karma-spec-reporter": "^0.0.36", diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts index d647be876d1..2282f260d4c 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts @@ -1639,17 +1639,12 @@ describe('IgxGrid - Row Selection #grid', () => { grid.notifyChanges(); fix.detectChanges(); - console.log('Selected rows after first selection:', grid.selectedRows); - GridSelectionFunctions.verifyHeaderRowCheckboxState(fix, false, true); GridSelectionFunctions.verifyRowSelected(firstRow); grid.paginator.nextPage(); fix.detectChanges(); - - console.log('Current page index after next page:', grid.paginator.page); - console.log('Selected rows after page change:', grid.selectedRows); - + GridSelectionFunctions.verifyHeaderRowCheckboxState(fix, false, true); GridSelectionFunctions.verifyRowsArraySelected(grid.rowList.toArray(), false); diff --git a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts index 0cef33c1b32..cd757f056ed 100644 --- a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts +++ b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts @@ -44,7 +44,6 @@ export class IgxGridSelectionService { private allRowsSelected: boolean; private _lastSelectedNode: ISelectionNode; - public lastSelectedRowIndex: number = -1; private _ranges: Set = new Set(); private _selectionRange: Range; @@ -418,7 +417,6 @@ export class IgxGridSelectionService { public getSelectedRows(): Array { return this.rowSelection.size ? Array.from(this.rowSelection.keys()) : []; } - /** Returns array of the rows in indeterminate state. */ public getIndeterminateRows(): Array { return this.indeterminateRows.size ? Array.from(this.indeterminateRows.keys()) : []; @@ -587,7 +585,7 @@ export class IgxGridSelectionService { return this.indeterminateRows.size > 0 && this.indeterminateRows.has(rowID); } - /** Select range from last selected row to the current specified row. */ + /** Select range from last selected row to the current specified row. */ public selectMultipleRows(rowID, rowData, event?): void { this.clearHeaderCBState(); if (!this.rowSelection.size || this.isRowDeleted(rowID)) { @@ -604,7 +602,7 @@ export class IgxGridSelectionService { const newSelection = currSelection.concat(added); this.emitRowSelectionEvent(newSelection, added, [], event, currSelection); } - + public areAllRowSelected(newSelection?): boolean { if (!this.grid.data && !newSelection) { return false; @@ -675,8 +673,6 @@ export class IgxGridSelectionService { return this.grid.primaryKey && data.length ? data.map(rec => rec[this.grid.primaryKey]) : data; } - - public getRecordKey(record) { return this.grid.primaryKey ? record[this.grid.primaryKey] : record; } From 774d4605a0c42d4fe0e496bf6fcd28a437e8d38c Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Tue, 16 Jan 2024 10:18:47 +0200 Subject: [PATCH 07/13] fix(grid): Formated and cleared code --- package.json | 1 - .../src/lib/grids/selection/selection.service.ts | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cb7b62e310d..fd0880226f5 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,6 @@ "express": "^4.18.2", "fflate": "^0.8.1", "hammerjs": "^2.0.8", - "igniteui-angular": "^17.0.8", "igniteui-theming": "^4.0.1", "igniteui-trial-watermark": "^3.0.2", "lodash-es": "^4.17.21", diff --git a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts index cd757f056ed..684811b7582 100644 --- a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts +++ b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts @@ -417,6 +417,7 @@ export class IgxGridSelectionService { public getSelectedRows(): Array { return this.rowSelection.size ? Array.from(this.rowSelection.keys()) : []; } + /** Returns array of the rows in indeterminate state. */ public getIndeterminateRows(): Array { return this.indeterminateRows.size ? Array.from(this.indeterminateRows.keys()) : []; From 18914dd2868067764016417e4590b3eb8f0a8e82 Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Tue, 16 Jan 2024 10:47:19 +0200 Subject: [PATCH 08/13] fix(grid): Removed white spaces --- .../src/lib/grids/grid/grid-row-selection.spec.ts | 2 +- .../src/lib/grids/selection/selection.service.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts index 2282f260d4c..ad3b8c18631 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts @@ -1644,7 +1644,7 @@ describe('IgxGrid - Row Selection #grid', () => { grid.paginator.nextPage(); fix.detectChanges(); - + GridSelectionFunctions.verifyHeaderRowCheckboxState(fix, false, true); GridSelectionFunctions.verifyRowsArraySelected(grid.rowList.toArray(), false); diff --git a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts index 684811b7582..6804808154f 100644 --- a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts +++ b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts @@ -417,7 +417,7 @@ export class IgxGridSelectionService { public getSelectedRows(): Array { return this.rowSelection.size ? Array.from(this.rowSelection.keys()) : []; } - + /** Returns array of the rows in indeterminate state. */ public getIndeterminateRows(): Array { return this.indeterminateRows.size ? Array.from(this.indeterminateRows.keys()) : []; From 290060143e03f508b4546890336905ec6cf3bb35 Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Tue, 16 Jan 2024 10:48:20 +0200 Subject: [PATCH 09/13] fix(grid): Removed white spaces --- .../src/lib/grids/selection/selection.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts index 6804808154f..8c3354f680a 100644 --- a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts +++ b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts @@ -603,7 +603,7 @@ export class IgxGridSelectionService { const newSelection = currSelection.concat(added); this.emitRowSelectionEvent(newSelection, added, [], event, currSelection); } - + public areAllRowSelected(newSelection?): boolean { if (!this.grid.data && !newSelection) { return false; From 628e621c022ba05fb7ab5bf440af88f01cd79315 Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Tue, 16 Jan 2024 10:51:22 +0200 Subject: [PATCH 10/13] fix(grid): Cleared package-lock.json --- package-lock.json | 47 ++--------------------------------------------- 1 file changed, 2 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index 46987883d09..87c38b803ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,12 +25,11 @@ "express": "^4.18.2", "fflate": "^0.8.1", "hammerjs": "^2.0.8", - "igniteui-angular": "^17.0.8", "igniteui-theming": "^4.0.1", "igniteui-trial-watermark": "^3.0.2", "lodash-es": "^4.17.21", "rxjs": "^6.6.7", - "tslib": "^2.6.2", + "tslib": "^2.3.0", "uuid": "^9.0.0", "zone.js": "~0.14.2" }, @@ -76,7 +75,6 @@ "karma-chrome-launcher": "~3.2.0", "karma-coverage": "^2.0.3", "karma-jasmine": "~5.1.0", - "karma-jasmine-spec-tags": "^2.0.0", "karma-junit-reporter": "^2.0.1", "karma-parallel": "^0.3.1", "karma-spec-reporter": "^0.0.36", @@ -12829,36 +12827,6 @@ "integrity": "sha512-hC5pinvq0ziDRZmrGRuXY8rJWjWv45Vj/utXFaiX5sAt+hifW7xFMTQPu679187EMe3HOHhaZc3K7vhy/8iPNA==", "dev": true }, - "node_modules/igniteui-angular": { - "version": "17.0.8", - "resolved": "https://registry.npmjs.org/igniteui-angular/-/igniteui-angular-17.0.8.tgz", - "integrity": "sha512-OgUMyhCRL7uO/9jHHepZxpHk4Iy4hr3Ju/Z3AQUPNuKQpN3HioPEhs4DlLaVN/VHQmRgYGxHNMNHSTVncw05xg==", - "dependencies": { - "@igniteui/material-icons-extended": "^3.0.0", - "@types/hammerjs": "^2.0.40", - "fflate": "^0.8.1", - "hammerjs": "^2.0.8", - "igniteui-theming": "^3.3.3", - "igniteui-trial-watermark": "^3.0.2", - "lodash-es": "^4.17.21", - "tslib": "^2.3.0", - "uuid": "^9.0.0" - }, - "peerDependencies": { - "@angular/animations": "^17.0.0", - "@angular/common": "^17.0.0", - "@angular/core": "^17.0.0", - "@angular/forms": "^17.0.0" - } - }, - "node_modules/igniteui-angular/node_modules/igniteui-theming": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/igniteui-theming/-/igniteui-theming-3.3.3.tgz", - "integrity": "sha512-f15sUvOvgzDuQjEdVy2onX4DVjYwa3g3MdtSspudf8WurlvLb54TK+bC/sEOfhfrTnaRMC/laGmRWfjD13ebkw==", - "peerDependencies": { - "sass": "^1.58.1" - } - }, "node_modules/igniteui-sassdoc-theme": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/igniteui-sassdoc-theme/-/igniteui-sassdoc-theme-1.2.3.tgz", @@ -14236,17 +14204,6 @@ "karma": "^6.0.0" } }, - "node_modules/karma-jasmine-spec-tags": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/karma-jasmine-spec-tags/-/karma-jasmine-spec-tags-2.0.0.tgz", - "integrity": "sha512-ckTZvS+w9LyYQtI/LY6nNS6oiuQM7bSRzJgLBwde5Ivr6k5uQ1y58HD77YQH9+rWIj048LXBpXk2VY3ws9hE2A==", - "dev": true, - "peerDependencies": { - "jasmine": ">=4 || >=5", - "karma": ">=6.0.4", - "karma-jasmine": "*" - } - }, "node_modules/karma-jasmine/node_modules/jasmine-core": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.6.0.tgz", @@ -24852,4 +24809,4 @@ } } } -} +} \ No newline at end of file From a4ccc6dc60c3b13f0292d80ba7241b23e1602aa4 Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Wed, 17 Jan 2024 15:14:17 +0200 Subject: [PATCH 11/13] test(grid): Added unit test for shift-click row selection with grouping --- .../lib/grids/grid/grid-row-selection.spec.ts | 49 ++++++++++++++++++- .../lib/grids/selection/selection.service.ts | 1 + 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts index ad3b8c18631..d047eb6b3c4 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts @@ -543,6 +543,53 @@ describe('IgxGrid - Row Selection #grid', () => { } }); + it('Should select the correct rows with Shift + Click when grouping is activated', () => { + expect(grid.selectRowOnClick).toBe(true); + spyOn(grid.rowSelectionChanging, 'emit').and.callThrough(); + + grid.groupBy({ + fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: false + }); + + fix.detectChanges(); + + const firstGroupRow = grid.gridAPI.get_row_by_index(1); + const lastGroupRow = grid.gridAPI.get_row_by_index(4); + + // Clicking on the first row within a group + UIInteractions.simulateClickEvent(firstGroupRow.nativeElement); + fix.detectChanges(); + + GridSelectionFunctions.verifyRowSelected(firstGroupRow); + + // Simulate Shift+Click on a row within another group + const mockEvent = new MouseEvent('click', { shiftKey: true }); + lastGroupRow.nativeElement.dispatchEvent(mockEvent); + fix.detectChanges(); + + expect(grid.selectedRows).toEqual([5, 14, 8]); // ids + expect(grid.rowSelectionChanging.emit).toHaveBeenCalledTimes(2); + expect(grid.rowSelectionChanging.emit).toHaveBeenCalledWith({ + added: [grid.dataView[2], grid.dataView[4]], + cancel: false, + event: jasmine.anything(), + newSelection: [grid.dataView[1], grid.dataView[2], grid.dataView[4]], + oldSelection: [grid.dataView[1]], + removed: [], + allRowsSelected: false, + owner: grid + }); + + const expectedSelectedRowIds = [5, 14, 8]; + grid.dataView.forEach((rowData, index) => { + if (expectedSelectedRowIds.includes(rowData.ProductID)) { + const row = grid.gridAPI.get_row_by_index(index); + GridSelectionFunctions.verifyRowSelected(row); + } + }); + + }); + it('Should NOT select multiple rows with Shift + Click when selectRowOnClick has false value', () => { grid.selectRowOnClick = false; spyOn(grid.rowSelectionChanging, 'emit').and.callThrough(); @@ -2222,7 +2269,7 @@ describe('IgxGrid - Row Selection #grid', () => { expect(fix.componentInstance.onHeaderCheckboxClick).toHaveBeenCalledTimes(2); expect(fix.componentInstance.onHeaderCheckboxClick). - toHaveBeenCalledWith(fix.componentInstance.headerCheckboxClick, contextUnselect); + toHaveBeenCalledWith(fix.componentInstance.headerCheckboxClick, contextUnselect); }); it('Should have correct indices on all pages', () => { diff --git a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts index 8c3354f680a..4d6d8648837 100644 --- a/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts +++ b/projects/igniteui-angular/src/lib/grids/selection/selection.service.ts @@ -689,6 +689,7 @@ export class IgxGridSelectionService { /** Returns all data in the grid, with applied filtering and sorting and without deleted rows. */ public get allData(): Array { let allData; + // V.T. Jan 17th, 2024 #13757 Adding an additional conditional check to take account WITHIN range of groups if (this.isFilteringApplied() || this.grid.sortingExpressions.length || this.grid.groupingExpressions?.length) { allData = this.grid.pinnedRecordsCount ? this.grid._filteredSortedUnpinnedData : this.grid.filteredSortedData; } else { From 0ae7b316dd45bd7ac96c7356561524475f46c750 Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Wed, 17 Jan 2024 15:29:54 +0200 Subject: [PATCH 12/13] style(grid): Removing whitespaces and formating --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 87c38b803ba..c166095ca9e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24809,4 +24809,4 @@ } } } -} \ No newline at end of file +} From 8069fee02416ef649d9cc00a53e746b5e726a909 Mon Sep 17 00:00:00 2001 From: valeriatoneva Date: Wed, 17 Jan 2024 15:33:54 +0200 Subject: [PATCH 13/13] style(grid): Correct minor typos --- .../src/lib/grids/grid/grid-row-selection.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts index d047eb6b3c4..a9711744fc5 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-row-selection.spec.ts @@ -2269,7 +2269,7 @@ describe('IgxGrid - Row Selection #grid', () => { expect(fix.componentInstance.onHeaderCheckboxClick).toHaveBeenCalledTimes(2); expect(fix.componentInstance.onHeaderCheckboxClick). - toHaveBeenCalledWith(fix.componentInstance.headerCheckboxClick, contextUnselect); + toHaveBeenCalledWith(fix.componentInstance.headerCheckboxClick, contextUnselect); }); it('Should have correct indices on all pages', () => {