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..72aa7cb0e666 100644
--- a/src/material/radio/radio.ts
+++ b/src/material/radio/radio.ts
@@ -42,6 +42,7 @@ import {BooleanInput, coerceBooleanProperty, coerceNumberProperty} from '@angula
import {UniqueSelectionDispatcher} from '@angular/cdk/collections';
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
+import {Subscription} from 'rxjs';
// Increasing integer for generating unique ids for radio components.
let nextUniqueId = 0;
@@ -100,7 +101,7 @@ export function MAT_RADIO_DEFAULT_OPTIONS_FACTORY(): MatRadioDefaultOptions {
*/
@Directive()
export abstract class _MatRadioGroupBase
- implements AfterContentInit, ControlValueAccessor
+ implements AfterContentInit, OnDestroy, ControlValueAccessor
{
/** Selected value for the radio group. */
private _value: any = null;
@@ -123,6 +124,9 @@ export abstract class _MatRadioGroupBase
/** Whether the radio group is required. */
private _required: boolean = false;
+ /** Subscription to changes in amount of radio buttons. */
+ private _buttonChanges: Subscription;
+
/** The method to be called in order to update ngModel */
_controlValueAccessorChangeFn: (value: any) => void = () => {};
@@ -236,6 +240,20 @@ export abstract class _MatRadioGroupBase
// possibly be set by NgModel on MatRadioGroup, and it is possible that the OnInit of the
// NgModel occurs *after* the OnInit of the MatRadioGroup.
this._isInitialized = true;
+
+ // Clear the `selected` button when it's destroyed since the tabindex of the rest of the
+ // buttons depends on it. Note that we don't clear the `value`, because the radio button
+ // may be swapped out with a similar one and there are some internal apps that depend on
+ // that behavior.
+ this._buttonChanges = this._radios.changes.subscribe(() => {
+ if (this.selected && !this._radios.find(radio => radio === this.selected)) {
+ this._selected = null;
+ }
+ });
+ }
+
+ ngOnDestroy() {
+ this._buttonChanges?.unsubscribe();
}
/**
diff --git a/tools/public_api_guard/material/radio.md b/tools/public_api_guard/material/radio.md
index fc19d0686502..5eade5af5fb8 100644
--- a/tools/public_api_guard/material/radio.md
+++ b/tools/public_api_guard/material/radio.md
@@ -124,7 +124,7 @@ export class MatRadioGroup extends _MatRadioGroupBase {
}
// @public
-export abstract class _MatRadioGroupBase implements AfterContentInit, ControlValueAccessor {
+export abstract class _MatRadioGroupBase implements AfterContentInit, OnDestroy, ControlValueAccessor {
constructor(_changeDetector: ChangeDetectorRef);
readonly change: EventEmitter;
// (undocumented)
@@ -141,6 +141,8 @@ export abstract class _MatRadioGroupBase implemen
get name(): string;
set name(value: string);
ngAfterContentInit(): void;
+ // (undocumented)
+ ngOnDestroy(): void;
onTouched: () => any;
abstract _radios: QueryList;
registerOnChange(fn: (value: any) => void): void;