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));