From 2bbd3273faae41f0d996937b0c2407a7d3b5a081 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Sun, 16 Jul 2023 12:40:08 +0200 Subject: [PATCH] fix(material/radio): clear selected radio button from group In #18081 the radio group was changed so that deselected buttons receive `tabindex="-1"` when there's a selected button. The problem is that we weren't clearing the reference to the selected button so it gets removed, the deselected buttons become unfocusable using the keyboard. These changes clear the selected radio button on destroy. Fixes #27461. --- src/material/radio/radio.spec.ts | 24 +++++++++++++++++++----- src/material/radio/radio.ts | 9 +++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/material/radio/radio.spec.ts b/src/material/radio/radio.spec.ts index 5aec8aef5b85..1e32fc0f1cad 100644 --- a/src/material/radio/radio.spec.ts +++ b/src/material/radio/radio.spec.ts @@ -471,6 +471,19 @@ describe('MDC-based MatRadio', () => { }), ).toEqual(['-1', '-1', '0']); }); + + it('should clear the selected radio button but preserve the value on destroy', () => { + radioLabelElements[0].click(); + fixture.detectChanges(); + expect(groupInstance.selected).toBe(radioInstances[0]); + expect(groupInstance.value).toBe('fire'); + + fixture.componentInstance.isFirstShown = false; + fixture.detectChanges(); + + expect(groupInstance.selected).toBe(null); + expect(groupInstance.value).toBe('fire'); + }); }); describe('group with ngModel', () => { @@ -995,7 +1008,7 @@ describe('MatRadioDefaultOverrides', () => { [value]="groupValue" name="test-name"> + [color]="color" *ngIf="isFirstShown"> Charmander @@ -1009,12 +1022,13 @@ describe('MatRadioDefaultOverrides', () => { }) class RadiosInsideRadioGroup { labelPos: 'before' | 'after'; - isFirstDisabled: boolean = false; - isGroupDisabled: boolean = false; - isGroupRequired: boolean = false; + isFirstDisabled = false; + isGroupDisabled = false; + isGroupRequired = false; groupValue: string | null = null; - disableRipple: boolean = false; + disableRipple = false; color: string | null; + isFirstShown = true; } @Component({ diff --git a/src/material/radio/radio.ts b/src/material/radio/radio.ts index 367bfbebbb86..a485ecc90aff 100644 --- a/src/material/radio/radio.ts +++ b/src/material/radio/radio.ts @@ -568,6 +568,15 @@ export abstract class _MatRadioButtonBase ngOnDestroy() { this._focusMonitor.stopMonitoring(this._elementRef); this._removeUniqueSelectionListener(); + + // Clear the button from the `selected` state since it determines the `tabindex` of the + // remaining radio buttons. Note that we preserve the old value, because there are some + // internal tests that depend on it. + if (this.radioGroup?.selected === this) { + const oldValue = this.radioGroup.value; + this.radioGroup.selected = null; + this.radioGroup.value = oldValue; + } } /** Dispatch change event with current value. */