From fe07e26e6edf17706e84cdf9adad1d79be62727b Mon Sep 17 00:00:00 2001 From: Christian Schulz Date: Thu, 20 Aug 2026 10:22:40 +0200 Subject: [PATCH] fix(material/chips): emit null instead of undefined when deselecting the only selected chip MatChipListbox._propagateChanges() emitted `undefined` as the control value whenever a single-select listbox went from one chip selected to none selected. Consumers that treat `undefined` and `null` differently (e.g. Angular Signal Forms, which uses `undefined` to mean "this field no longer exists" internally) can crash on this transition. Emit `null` instead, matching the "nothing selected" convention already used elsewhere in Angular forms (e.g. FormControl's own initial value). The multi-select branch is unaffected: it already emits `[]` for an empty selection. --- src/material/chips/chip-listbox.spec.ts | 20 ++++++++++++++++++++ src/material/chips/chip-listbox.ts | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/material/chips/chip-listbox.spec.ts b/src/material/chips/chip-listbox.spec.ts index 592c7ca66b98..0779d1f42a5c 100644 --- a/src/material/chips/chip-listbox.spec.ts +++ b/src/material/chips/chip-listbox.spec.ts @@ -652,6 +652,26 @@ describe('MatChipListbox', () => { .toEqual('steak-0'); }); + it('should propagate null, not undefined, when the selected chip is deselected', () => { + dispatchKeyboardEvent(primaryActions[0], 'keydown', SPACE); + fixture.detectChanges(); + + expect(fixture.componentInstance.control.value) + .withContext(`Expected control's value to be set to the new option.`) + .toEqual('steak-0'); + + dispatchKeyboardEvent(primaryActions[0], 'keydown', SPACE); + fixture.detectChanges(); + + expect(fixture.componentInstance.control.value) + .withContext( + `Expected control's value to be null after deselecting the only selected ` + + `chip, not undefined - consumers (e.g. Angular Signal Forms) treat a value of ` + + `undefined as "this field no longer exists" rather than "this field is empty".`, + ) + .toEqual(null); + }); + it('should clear the selection when a nonexistent option value is selected', () => { const array = chips.toArray(); diff --git a/src/material/chips/chip-listbox.ts b/src/material/chips/chip-listbox.ts index 14b44a3a4f68..2f700dde84ba 100644 --- a/src/material/chips/chip-listbox.ts +++ b/src/material/chips/chip-listbox.ts @@ -321,7 +321,7 @@ export class MatChipListbox if (Array.isArray(this.selected)) { valueToEmit = this.selected.map(chip => chip.value); } else { - valueToEmit = this.selected ? this.selected.value : undefined; + valueToEmit = this.selected ? this.selected.value : null; } this._value = valueToEmit; this.change.emit(new MatChipListboxChange(this, valueToEmit));