From 5e68eeb46ec8ed68bfc6b6f318ba3d9130df51b8 Mon Sep 17 00:00:00 2001 From: Wagner Maciel Date: Wed, 20 Aug 2025 10:34:03 -0400 Subject: [PATCH] fix(cdk-experimental/ui-patterns): deselectAll unavailable items * Change deselectAll to deselect values that are not accounted for in the items array. --- .../list-selection/list-selection.spec.ts | 7 +++++++ .../list-selection/list-selection.ts | 21 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/cdk-experimental/ui-patterns/behaviors/list-selection/list-selection.spec.ts b/src/cdk-experimental/ui-patterns/behaviors/list-selection/list-selection.spec.ts index 65336685ea1e..9c36aad62a9e 100644 --- a/src/cdk-experimental/ui-patterns/behaviors/list-selection/list-selection.spec.ts +++ b/src/cdk-experimental/ui-patterns/behaviors/list-selection/list-selection.spec.ts @@ -168,6 +168,13 @@ describe('List Selection', () => { selection.deselectAll(); // [] expect(selection.inputs.value().length).toBe(0); }); + + it('should deselect items that are not in the list', () => { + const selection = getSelection({multi: signal(true)}); + selection.inputs.value.update(() => [5]); + selection.deselectAll(); + expect(selection.inputs.value().length).toBe(0); + }); }); describe('#toggleAll', () => { diff --git a/src/cdk-experimental/ui-patterns/behaviors/list-selection/list-selection.ts b/src/cdk-experimental/ui-patterns/behaviors/list-selection/list-selection.ts index b823b7d924eb..0ad0e2b5db1d 100644 --- a/src/cdk-experimental/ui-patterns/behaviors/list-selection/list-selection.ts +++ b/src/cdk-experimental/ui-patterns/behaviors/list-selection/list-selection.ts @@ -102,8 +102,25 @@ export class ListSelection, V> { /** Deselects all items in the list. */ deselectAll() { - for (const item of this.inputs.items()) { - this.deselect(item); + // If an item is not in the list, it forcefully gets deselected. + // This actually creates a bug for the following edge case: + // + // Setup: An item is not in the list (maybe it's lazily loaded), and it is disabled & selected. + // Expected: If deselectAll() is called, it should NOT get deselected (because it is disabled). + // Actual: Calling deselectAll() will still deselect the item. + // + // Why? Because we can't check if the item is disabled if it's not in the list. + // + // Alternatively, we could NOT deselect items that are not in the list, but this has the + // inverse (and more common) effect of keeping enabled items selected when they aren't in the + // list. + + for (const value of this.inputs.value()) { + const item = this.inputs.items().find(i => i.value() === value); + + item + ? this.deselect(item) + : this.inputs.value.update(values => values.filter(v => v !== value)); } }