diff --git a/src/cdk/collections/selection-model.ts b/src/cdk/collections/selection-model.ts index c5ac4daff494..fa295aea5b49 100644 --- a/src/cdk/collections/selection-model.ts +++ b/src/cdk/collections/selection-model.ts @@ -208,11 +208,16 @@ export class SelectionModel { /** Deselects a value. */ private _unmarkSelected(value: T) { + let comparableValue: T | null = null; if (this.isSelected(value)) { - this._selection.delete(value); - + if (this.compareWith) { + comparableValue = this._getComparableValue(value) as T; + this._selection.delete(comparableValue); + } else { + this._selection.delete(value); + } if (this._emitChanges) { - this._deselectedToEmit.push(value); + this._deselectedToEmit.push(comparableValue || value); } } } @@ -238,6 +243,19 @@ export class SelectionModel { private _hasQueuedChanges() { return !!(this._deselectedToEmit.length || this._selectedToEmit.length); } + + /** Returns a value that is comparable to inputValue by applying compareWith function, returns null if none.*/ + private _getComparableValue(inputValue: T): T | null { + let comparableValue: T | null = null; + if (this.compareWith) { + this._selection.forEach(selectedValue => { + if (this.compareWith?.call(undefined, inputValue, selectedValue)) { + comparableValue = selectedValue; + } + }); + } + return comparableValue; + } } /** diff --git a/src/cdk/collections/selection.spec.ts b/src/cdk/collections/selection.spec.ts index ac430f962f23..3242865ff8ef 100644 --- a/src/cdk/collections/selection.spec.ts +++ b/src/cdk/collections/selection.spec.ts @@ -279,4 +279,24 @@ describe('SelectionModel', () => { let singleSelectionModel = new SelectionModel(); expect(singleSelectionModel.isMultipleSelection()).toBe(false); }); + + it('should deselect value if comparable to another one', () => { + type T = {key: number; value: string}; + const v1: T = {key: 1, value: 'blue'}; + const v2: T = {key: 1, value: 'green'}; + const compareFun = (x: T, y: T) => x.key === y.key; + const model = new SelectionModel(false, [v1], false, compareFun); + model.deselect(v2); + expect(model.selected.length).toBe(0); + }); + + it('should not deselect value if not comparable to another one', () => { + type T = {key: number; value: string}; + const v1: T = {key: 1, value: 'blue'}; + const v2: T = {key: 2, value: 'apple'}; + const compareFun = (x: T, y: T) => x.key === y.key; + const model = new SelectionModel(false, [v1], false, compareFun); + model.deselect(v2); + expect(model.selected.length).toBe(1); + }); });