diff --git a/demos/aurelia/test/cypress/e2e/example32.cy.ts b/demos/aurelia/test/cypress/e2e/example32.cy.ts index 1c8eb7b69..029f3035b 100644 --- a/demos/aurelia/test/cypress/e2e/example32.cy.ts +++ b/demos/aurelia/test/cypress/e2e/example32.cy.ts @@ -115,8 +115,9 @@ describe('Example 32 - Columns Resize by Content', () => { cy.get('#filter-checkbox-selectall-container input[type=checkbox]').click({ force: true }); cy.window().then((win) => { - expect(win.console.log).to.have.callCount(3); + const selectedIdsCalls = (win.console.log as any).getCalls().filter((call: any) => call.args[0] === 'Selected Ids:'); expect(win.console.log).to.be.calledWith('Selected Ids:', expectedRowIds); + expect(selectedIdsCalls.some((call: any) => call.args[1]?.length === 401)).to.be.true; }); }); diff --git a/demos/react/test/cypress/e2e/example32.cy.ts b/demos/react/test/cypress/e2e/example32.cy.ts index 1c8eb7b69..029f3035b 100644 --- a/demos/react/test/cypress/e2e/example32.cy.ts +++ b/demos/react/test/cypress/e2e/example32.cy.ts @@ -115,8 +115,9 @@ describe('Example 32 - Columns Resize by Content', () => { cy.get('#filter-checkbox-selectall-container input[type=checkbox]').click({ force: true }); cy.window().then((win) => { - expect(win.console.log).to.have.callCount(3); + const selectedIdsCalls = (win.console.log as any).getCalls().filter((call: any) => call.args[0] === 'Selected Ids:'); expect(win.console.log).to.be.calledWith('Selected Ids:', expectedRowIds); + expect(selectedIdsCalls.some((call: any) => call.args[1]?.length === 401)).to.be.true; }); }); diff --git a/demos/vue/test/cypress/e2e/example32.cy.ts b/demos/vue/test/cypress/e2e/example32.cy.ts index 1c8eb7b69..029f3035b 100644 --- a/demos/vue/test/cypress/e2e/example32.cy.ts +++ b/demos/vue/test/cypress/e2e/example32.cy.ts @@ -115,8 +115,9 @@ describe('Example 32 - Columns Resize by Content', () => { cy.get('#filter-checkbox-selectall-container input[type=checkbox]').click({ force: true }); cy.window().then((win) => { - expect(win.console.log).to.have.callCount(3); + const selectedIdsCalls = (win.console.log as any).getCalls().filter((call: any) => call.args[0] === 'Selected Ids:'); expect(win.console.log).to.be.calledWith('Selected Ids:', expectedRowIds); + expect(selectedIdsCalls.some((call: any) => call.args[1]?.length === 401)).to.be.true; }); }); diff --git a/frameworks/angular-slickgrid/test/cypress/e2e/example32.cy.ts b/frameworks/angular-slickgrid/test/cypress/e2e/example32.cy.ts index aaca83d64..53e74e76e 100644 --- a/frameworks/angular-slickgrid/test/cypress/e2e/example32.cy.ts +++ b/frameworks/angular-slickgrid/test/cypress/e2e/example32.cy.ts @@ -115,8 +115,9 @@ describe('Example 32 - Columns Resize by Content', () => { cy.get('#filter-checkbox-selectall-container input[type=checkbox]').click({ force: true }); cy.window().then((win) => { - expect(win.console.log).to.have.callCount(3); + const selectedIdsCalls = (win.console.log as any).getCalls().filter((call: any) => call.args[0] === 'Selected Ids:'); expect(win.console.log).to.be.calledWith('Selected Ids:', expectedRowIds); + expect(selectedIdsCalls.some((call: any) => call.args[1]?.length === 401)).to.be.true; }); }); diff --git a/packages/common/src/core/__tests__/slickDataView.spec.ts b/packages/common/src/core/__tests__/slickDataView.spec.ts index 80124d492..466027759 100644 --- a/packages/common/src/core/__tests__/slickDataView.spec.ts +++ b/packages/common/src/core/__tests__/slickDataView.spec.ts @@ -2197,6 +2197,85 @@ describe('SlickDatView core file', () => { ]); }); + it('should report all filtered selected IDs when selection changes through the grid', () => { + const columns = [ + { id: 'name', field: 'name', name: 'Name' }, + { id: 'age', field: 'age', name: 'Age' }, + ]; + const gridOptions = { enableCellNavigation: true, multiSelect: true, devMode: { ownerNodeIndex: 0 } } as GridOption; + dv = new SlickDataView({}); + const grid = new SlickGrid('#myGrid', dv, columns, gridOptions); + const onSelectedRowIdsSpy = vi.spyOn(dv.onSelectedRowIdsChanged, 'notify'); + grid.setSelectionModel(new SlickHybridSelectionModel({ selectActiveRow: false, selectionType: 'row' })); + dv.setItems(items); + dv.setPagingOptions({ dataView: dv, pageNum: 0, pageSize: 4 }); + dv.syncGridSelection(grid, false, true); + dv.setSelectedIds([3, 4, 8], { isRowBeingAdded: true, applyRowSelectionToGrid: true }); + onSelectedRowIdsSpy.mockClear(); + + grid.setSelectedRows([0, 1, 2]); + + expect(onSelectedRowIdsSpy).toHaveBeenLastCalledWith(expect.objectContaining({ filteredIds: [4, 3, 1, 8] }), expect.anything(), dv); + }); + + it('should normalize an existing unsorted selection when the same IDs are selected again', () => { + const columns = [ + { id: 'name', field: 'name', name: 'Name' }, + { id: 'age', field: 'age', name: 'Age' }, + ]; + const gridOptions = { enableCellNavigation: true, multiSelect: true, devMode: { ownerNodeIndex: 0 } } as GridOption; + dv = new SlickDataView({}); + const grid = new SlickGrid('#myGrid', dv, columns, gridOptions); + grid.setSelectionModel(new SlickHybridSelectionModel({ selectActiveRow: false, selectionType: 'row' })); + dv.setItems(items); + grid.setSelectedRows([0, 1]); + dv.syncGridSelection(grid, false, true); + + dv.setSelectedIds([3, 4], { isRowBeingAdded: true, applyRowSelectionToGrid: false }); + + expect(dv.getAllSelectedIds()).toEqual([3, 4]); + }); + + it('should reuse pending filtered IDs for bulk grid selection', () => { + const columns = [ + { id: 'name', field: 'name', name: 'Name' }, + { id: 'age', field: 'age', name: 'Age' }, + ]; + const gridOptions = { enableCellNavigation: true, multiSelect: true, devMode: { ownerNodeIndex: 0 } } as GridOption; + dv = new SlickDataView({}); + const grid = new SlickGrid('#myGrid', dv, columns, gridOptions); + const onSelectedRowIdsSpy = vi.spyOn(dv.onSelectedRowIdsChanged, 'notify'); + grid.setSelectionModel(new SlickHybridSelectionModel({ selectActiveRow: false, selectionType: 'row' })); + dv.setItems(items); + dv.setPagingOptions({ dataView: dv, pageNum: 0, pageSize: 4 }); + dv.syncGridSelection(grid, false, true); + dv.setSelectedIds([3, 4, 8], { isRowBeingAdded: true, shouldTriggerEvent: false, applyRowSelectionToGrid: false }); + + grid.setSelectedRows([0, 1], 'click.selectAll'); + + expect(onSelectedRowIdsSpy).toHaveBeenLastCalledWith(expect.objectContaining({ filteredIds: [3, 4, 8] }), expect.anything(), dv); + }); + + it('should ignore pending filtered IDs when bulk grid selection changes the selected IDs', () => { + const columns = [ + { id: 'name', field: 'name', name: 'Name' }, + { id: 'age', field: 'age', name: 'Age' }, + ]; + const gridOptions = { enableCellNavigation: true, multiSelect: true, devMode: { ownerNodeIndex: 0 } } as GridOption; + dv = new SlickDataView({}); + const grid = new SlickGrid('#myGrid', dv, columns, gridOptions); + const onSelectedRowIdsSpy = vi.spyOn(dv.onSelectedRowIdsChanged, 'notify'); + grid.setSelectionModel(new SlickHybridSelectionModel({ selectActiveRow: false, selectionType: 'row' })); + dv.setItems(items); + dv.setPagingOptions({ dataView: dv, pageNum: 0, pageSize: 4 }); + dv.syncGridSelection(grid, false, true); + dv.setSelectedIds([8], { isRowBeingAdded: true, shouldTriggerEvent: false, applyRowSelectionToGrid: false }); + + grid.setSelectedRows([0, 1], 'click.selectAll'); + + expect(onSelectedRowIdsSpy).toHaveBeenLastCalledWith(expect.objectContaining({ filteredIds: [4, 3, 8] }), expect.anything(), dv); + }); + it('should not expect row selections to be preserved when using "multiSelect:false" and setSelectedIds() even when either preseve is enabled ("preserveHidden" or "preserveHiddenOnSelectionChange")', () => { const columns = [ { id: 'name', field: 'name', name: 'Name' }, diff --git a/packages/common/src/core/__tests__/slickGrid.spec.ts b/packages/common/src/core/__tests__/slickGrid.spec.ts index 5da0e9c8c..6dde0f72b 100644 --- a/packages/common/src/core/__tests__/slickGrid.spec.ts +++ b/packages/common/src/core/__tests__/slickGrid.spec.ts @@ -30,6 +30,15 @@ class TestGrid extends SlickGrid { public callGetFormatter(row: number, column: Column) { return this.getFormatter(row, column); } + public callRowsToRanges(rows: number[], compactRows = false) { + return this.rowsToRanges(rows, compactRows); + } + public callAppendSelectedCellHtml(row: number, cell: number) { + const divRow = document.createElement('div'); + this.selectedRanges = [new SlickRange(row, cell)]; + this.appendCellHtml(divRow, row, cell, 1, 1, null, this.getDataItem(row)); + return divRow.firstElementChild as HTMLDivElement; + } public setCurrentEditorNull() { (this as any).currentEditor = null; } @@ -969,6 +978,38 @@ describe('SlickGrid core file', () => { expect(secondRowItemCell.classList.contains('selected')).toBeTruthy(); }); + it('should compact contiguous row ranges when Select All is clicked', () => { + const rowSelectionModel = new SlickHybridSelectionModel({ selectionType: 'row' }); + const setRangeSpy = vi.spyOn(rowSelectionModel, 'setSelectedRanges'); + + grid = new SlickGrid(container, data, columns, defaultOptions); + grid.setSelectionModel(rowSelectionModel); + vi.spyOn(grid.getEditorLock(), 'isActive').mockReturnValueOnce(false); + + grid.setSelectedRows([0, 1], 'click.selectAll'); + + expect(setRangeSpy).toHaveBeenCalledWith([new SlickRange(0, 0, 1, 0)], 'click.selectAll'); + }); + + it('should compact non-contiguous ascending rows and allow an empty selection', () => { + grid = new TestGrid(container, data, columns, defaultOptions); + + expect((grid as TestGrid).callRowsToRanges([0, 2], true)).toEqual([new SlickRange(0, 0, 0, 0), new SlickRange(2, 0, 2, 0)]); + expect((grid as TestGrid).callRowsToRanges([], true)).toEqual([]); + }); + + it('should retain legacy selection order when Select All receives non-ascending rows', () => { + const rowSelectionModel = new SlickHybridSelectionModel({ selectionType: 'row' }); + + grid = new SlickGrid(container, data, columns, defaultOptions); + grid.setSelectionModel(rowSelectionModel); + vi.spyOn(grid.getEditorLock(), 'isActive').mockReturnValueOnce(false); + + grid.setSelectedRows([2, 1], 'click.selectAll'); + + expect(grid.getSelectedRows()).toEqual([1, 2]); + }); + it('should select rows when the last column is hidden', () => { const columnsWithHiddenLastColumn = [ { id: 'firstName', field: 'firstName', name: 'First Name' }, @@ -984,6 +1025,24 @@ describe('SlickGrid core file', () => { expect(grid.getSelectedRows()).toEqual([1]); }); + it('should add selected CSS when rendering a selected cell without a CSS hash', () => { + grid = new TestGrid(container, data, columns, defaultOptions); + + const cell = (grid as TestGrid).callAppendSelectedCellHtml(1, 0); + + expect(cell.classList.contains('selected')).toBeTruthy(); + }); + + it('should add selected CSS alongside an existing cell CSS hash', () => { + grid = new TestGrid(container, data, columns, defaultOptions); + grid.setCellCssStyles('highlight', { 1: { firstName: 'highlight' } }); + + const cell = (grid as TestGrid).callAppendSelectedCellHtml(1, 0); + + expect(cell.classList).toContain('highlight'); + expect(cell.classList).toContain('selected'); + }); + it('should call SlickHybridSelectionModel.onDragReplaceCells() when selection mode is REP and range is expanding', () => { const hybridSelectionModel = new SlickHybridSelectionModel(); hybridSelectionModel.activeSelectionIsRow = true; diff --git a/packages/common/src/core/slickDataView.ts b/packages/common/src/core/slickDataView.ts index ca702bdb0..70f4947d0 100644 --- a/packages/common/src/core/slickDataView.ts +++ b/packages/common/src/core/slickDataView.ts @@ -156,6 +156,7 @@ export class SlickDataView implements CustomD protected toggledGroupsByLevel: any[] = []; protected groupingDelimiter = ':|:'; protected selectedRowIds: DataIdType[] = []; + protected pendingSelectedFilteredIds?: { ids: DataIdType[]; selectedRowIds: DataIdType[] }; protected preSelectedRowIdsChangeFn?: (args?: any) => void; protected pagesize = 0; @@ -1392,8 +1393,21 @@ export class SlickDataView implements CustomD if (rowIds === false) { this.selectedRowIds = []; } else { - if (this.selectedRowIds!.sort().join(',') !== rowIds.sort().join(',')) { - this.selectedRowIds = rowIds; + const sortedRowIds = rowIds.every((id, index) => index === 0 || `${rowIds[index - 1]}` <= `${id}`) ? rowIds : rowIds.slice().sort(); + const sortedSelectedRowIds = this.selectedRowIds!.every( + (id, index) => index === 0 || `${this.selectedRowIds![index - 1]}` <= `${id}` + ) + ? this.selectedRowIds + : this.selectedRowIds!.slice().sort(); + let selectedRowIdsChanged = this.selectedRowIds!.length !== sortedRowIds.length; + if (!selectedRowIdsChanged) { + const selectedRowIdsSet = new Set(this.selectedRowIds); + selectedRowIdsChanged = sortedRowIds.some((id) => !selectedRowIdsSet.has(id)); + } + if (selectedRowIdsChanged) { + this.selectedRowIds = sortedRowIds; + } else if (sortedSelectedRowIds !== this.selectedRowIds) { + this.selectedRowIds = sortedSelectedRowIds; } } }; @@ -1435,10 +1449,17 @@ export class SlickDataView implements CustomD dataView: this, }; this.preSelectedRowIdsChangeFn!(selectedRowsChangedArgs); + const isBulkSelection = args.caller === 'click.selectAll' || args.caller === 'click.unselectAll'; + const pendingSelectedFilteredIds = this.pendingSelectedFilteredIds; + const filteredIds = + isBulkSelection && pendingSelectedFilteredIds?.selectedRowIds === this.selectedRowIds + ? pendingSelectedFilteredIds.ids + : (this.getAllSelectedFilteredIds() as DataIdType[]); + this.pendingSelectedFilteredIds = undefined; this.onSelectedRowIdsChanged.notify( Object.assign(selectedRowsChangedArgs, { selectedRowIds: this.selectedRowIds, - filteredIds: this.getAllSelectedFilteredIds() as DataIdType[], + filteredIds, }), new SlickEventData(), this @@ -1532,6 +1553,10 @@ export class SlickDataView implements CustomD }; this.preSelectedRowIdsChangeFn?.(selectedRowsChangedArgs); + if (shouldTriggerEvent === false && applyRowSelectionToGrid === false) { + this.pendingSelectedFilteredIds = { ids: isRowBeingAdded ? selectedIds.slice() : [], selectedRowIds: this.selectedRowIds }; + } + if (shouldTriggerEvent !== false) { this.onSelectedRowIdsChanged.notify( Object.assign(selectedRowsChangedArgs, { diff --git a/packages/common/src/core/slickGrid.ts b/packages/common/src/core/slickGrid.ts index f8b844f54..9830b5f77 100755 --- a/packages/common/src/core/slickGrid.ts +++ b/packages/common/src/core/slickGrid.ts @@ -3543,7 +3543,10 @@ export class SlickGrid = Column, O e protected handleSelectedRangesChanged(e: SlickEventData, ranges: SlickRange[]): void { const ne = e.getNativeEvent(); const selectionMode: CellSelectionMode = ne?.detail?.selectionMode ?? ''; + const caller = ne?.detail?.caller ?? 'click'; + const isBulkSelection = caller === 'click.selectAll' || caller === 'click.unselectAll'; let addDragHandle = !!ne?.detail?.addDragHandle; + const selectedCellCssClass = this._options.selectedCellCssClass || ''; const selectionType = this.getSelectionModel()?.getOptions()?.selectionType; const showDragHandle = this.getDragHandleVisibility(); @@ -3590,48 +3593,60 @@ export class SlickGrid = Column, O e this.dragReplaceEl.removeEl(); this.selectedRows = []; const hash: CssStyleHash = Object.create(null); + const selectedRowsSet = ranges.length > 1 ? new Set() : undefined; + let rangesAreOrdered = true; for (let i = 0; i < ranges.length; i++) { + if (i > 0 && ranges[i - 1].toRow >= ranges[i].fromRow) { + rangesAreOrdered = false; + } for (let j = ranges[i].fromRow; j <= ranges[i].toRow; j++) { - if (!hash[j]) { - // prevent duplicates + if (!selectedRowsSet || !selectedRowsSet.has(j)) { + selectedRowsSet?.add(j); this.selectedRows.push(j); - hash[j] = Object.create(null); } + const rowHash = this.rowsCache[j] ? (hash[j] ??= Object.create(null)) : undefined; for (let k = ranges[i].fromCell; k <= ranges[i].toCell; k++) { - if (this.canCellBeSelected(j, k)) { - hash[j][this.columns[k].id] = this._options.selectedCellCssClass; + if (rowHash && this.canCellBeSelected(j, k)) { + rowHash[this.columns[k].id] = selectedCellCssClass; } } } } + if (!isBulkSelection || !rangesAreOrdered) { + // Preserve the legacy default sort order (numeric values are compared as strings). + this.selectedRows.sort(); + } + const activeRange = ranges[ranges.length - 1]; if (activeRange) { this.selectionBottomRow = activeRange.toRow; this.selectionRightCell = activeRange.toCell; } - this.setCellCssStyles(this._options.selectedCellCssClass || '', hash); + this.setCellCssStyles(selectedCellCssClass, hash); if (this.selectionBottomRow >= 0 && this.selectionRightCell >= 0 && addDragHandle && showDragHandle !== false) { const lowerRightCell = this.getCellNode(this.selectionBottomRow, this.selectionRightCell); this.dragReplaceEl.createEl(lowerRightCell, showDragHandle); } - // check if the selected rows have changed (index order isn't important, so we'll sort them both before comparing them) - if (!this.arrayEquals(previousSelectedRows.sort(), this.selectedRows.sort())) { - const caller = ne?.detail?.caller ?? 'click'; - // Use Set for faster performance - const selectedRowsSet = new Set(this.getSelectedRows()); + let selectedRowsChanged = previousSelectedRows.length !== this.selectedRows.length; + if (!selectedRowsChanged) { const previousSelectedRowsSet = new Set(previousSelectedRows); - - const newSelectedAdditions = Array.from(selectedRowsSet).filter((i) => !previousSelectedRowsSet.has(i)); - const newSelectedDeletions = Array.from(previousSelectedRowsSet).filter((i) => !selectedRowsSet.has(i)); + selectedRowsChanged = this.selectedRows.some((row) => !previousSelectedRowsSet.has(row)); + } + if (selectedRowsChanged) { + const selectedRows = this.getSelectedRows(); + const selectedRowsSet = selectedRows.length ? new Set(selectedRows) : undefined; + const previousSelectedRowsSet = previousSelectedRows.length ? new Set(previousSelectedRows) : undefined; + const newSelectedAdditions = previousSelectedRowsSet ? selectedRows.filter((i) => !previousSelectedRowsSet.has(i)) : selectedRows; + const newSelectedDeletions = selectedRowsSet ? previousSelectedRows.filter((i) => !selectedRowsSet.has(i)) : previousSelectedRows; this.triggerEvent( this.onSelectedRowsChanged, { - rows: this.getSelectedRows(), + rows: selectedRows, previousSelectedRows, caller, changedSelectedRows: newSelectedAdditions, @@ -4539,6 +4554,9 @@ export class SlickGrid = Column, O e if (cellCssClasses) { cellCss += ` ${cellCssClasses}`; } + if (this.isCellSelected(row, cell) && !cellCssClasses?.includes(this._options.selectedCellCssClass || '')) { + cellCss += ` ${this._options.selectedCellCssClass}`; + } let value: any = null; let formatterResult: FormatterResultWithHtml | FormatterResultWithText | HTMLElement | DocumentFragment | string = ''; @@ -6313,6 +6331,14 @@ export class SlickGrid = Column, O e return this.cellCssClasses[key]; } + protected isCellSelected(row: number, cell: number): boolean { + return ( + !!this._options.selectedCellCssClass && + this.selectedRanges.some((range) => range.contains(row, cell)) && + this.canCellBeSelected(row, cell) + ); + } + /** * Flashes the cell twice by toggling the CSS class 4 times. * @param {Number} row A row index. @@ -8322,12 +8348,30 @@ export class SlickGrid = Column, O e return true; } - protected rowsToRanges(rows: number[]): SlickRange[] { - const ranges: SlickRange[] = []; + protected rowsToRanges(rows: number[], compactRows = false): SlickRange[] { const columns = this.getVisibleColumns(); const lastCell = this.getColumnIndex(columns[columns.length - 1].id); - for (let i = 0; i < rows.length; i++) { - ranges.push(new SlickRange(rows[i], 0, rows[i], lastCell)); + const ranges: SlickRange[] = []; + if (!compactRows) { + rows.forEach((row) => ranges.push(new SlickRange(row, 0, row, lastCell))); + return ranges; + } + + let rangeStart = rows[0]; + let previousRow = rangeStart; + for (let i = 1; i < rows.length; i++) { + const row = rows[i]; + if (row <= previousRow) { + return rows.map((row) => new SlickRange(row, 0, row, lastCell)); + } + if (row !== previousRow + 1) { + ranges.push(new SlickRange(rangeStart, 0, previousRow, lastCell)); + rangeStart = row; + } + previousRow = row; + } + if (rangeStart !== undefined) { + ranges.push(new SlickRange(rangeStart, 0, previousRow, lastCell)); } return ranges; } @@ -8352,7 +8396,7 @@ export class SlickGrid = Column, O e const elock = this.getEditorLock(); if (typeof elock?.isActive === 'function' && !elock.isActive()) { - this.selectionModel.setSelectedRanges(this.rowsToRanges(rows), caller || 'SlickGrid.setSelectedRows'); + this.selectionModel.setSelectedRanges(this.rowsToRanges(rows, caller === 'click.selectAll'), caller || 'SlickGrid.setSelectedRows'); } } diff --git a/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts b/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts index ed4f17289..6ded8d006 100644 --- a/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts +++ b/packages/common/src/extensions/__tests__/slickCheckboxSelectColumn.spec.ts @@ -331,7 +331,7 @@ describe('SlickCheckboxSelectColumn Plugin', () => { expect(setSelectedRowSpy).toHaveBeenCalledWith([0, 2], 'click.selectAll'); expect(onToggleStartMock).toHaveBeenCalledWith(expect.anything(), { caller: 'click.selectAll', previousSelectedRows: undefined }); expect(onToggleEndMock).toHaveBeenCalledWith(expect.anything(), { caller: 'click.selectAll', previousSelectedRows: undefined, rows: [0, 2] }); - expect(setSelectedIdsSpy).toHaveBeenCalledWith([22], { isRowBeingAdded: true }); + expect(setSelectedIdsSpy).toHaveBeenCalledWith([22], { isRowBeingAdded: true, shouldTriggerEvent: false, applyRowSelectionToGrid: false }); }); it('should create the plugin and call "setOptions" and expect options changed and hide both Select All toggle when setting "hideSelectAllCheckbox: false" and "hideInColumnTitleRow: true"', () => { @@ -1064,6 +1064,6 @@ describe('SlickCheckboxSelectColumn Plugin', () => { expect(setSelectedRowSpy).toHaveBeenCalledWith([0, 2], 'click.selectAll'); expect(onToggleStartMock).toHaveBeenCalledWith(expect.anything(), { caller: 'click.selectAll', previousSelectedRows: [] }); expect(onToggleEndMock).toHaveBeenCalledWith(expect.anything(), { caller: 'click.selectAll', previousSelectedRows: [], rows: [0, 2] }); - expect(setSelectedIdsSpy).toHaveBeenCalledWith([22], { isRowBeingAdded: true }); + expect(setSelectedIdsSpy).toHaveBeenCalledWith([22], { isRowBeingAdded: true, shouldTriggerEvent: false, applyRowSelectionToGrid: false }); }); }); diff --git a/packages/common/src/extensions/slickCheckboxSelectColumn.ts b/packages/common/src/extensions/slickCheckboxSelectColumn.ts index 1cf24fff5..8e8ddfeda 100644 --- a/packages/common/src/extensions/slickCheckboxSelectColumn.ts +++ b/packages/common/src/extensions/slickCheckboxSelectColumn.ts @@ -549,7 +549,7 @@ export class SlickCheckboxSelectColumn { ids.push(dataviewRowItem[this._dataView.getIdPropertyName()]); } } - this._dataView.setSelectedIds(ids, { isRowBeingAdded: isAllSelected }); + this._dataView.setSelectedIds(ids, { isRowBeingAdded: isAllSelected, shouldTriggerEvent: false, applyRowSelectionToGrid: false }); } // we finally need to call the actual row selection from SlickGrid method diff --git a/test/cypress/e2e/example14.cy.ts b/test/cypress/e2e/example14.cy.ts index 35a490b96..fffe88656 100644 --- a/test/cypress/e2e/example14.cy.ts +++ b/test/cypress/e2e/example14.cy.ts @@ -125,8 +125,9 @@ describe('Example 14 - Columns Resize by Content', () => { cy.get('#filter-checkbox-selectall-container input[type=checkbox]').click({ force: true }); cy.window().then((win) => { - expect(win.console.log).to.have.callCount(6); + const selectedIdsCalls = (win.console.log as any).getCalls().filter((call: any) => call.args[0] === 'Selected Ids:'); expect(win.console.log).to.be.calledWith('Selected Ids:', expectedRowIds); + expect(selectedIdsCalls.some((call: any) => call.args[1]?.length === 401)).to.be.true; }); });