Skip to content

fix(material/radio): radio not preselected with static value and an ngIf #25852

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/material/legacy-radio/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ ng_test_library(
":legacy-radio",
"//src/cdk/testing/private",
"//src/material/radio",
"@npm//@angular/common",
"@npm//@angular/forms",
"@npm//@angular/platform-browser",
],
Expand Down
39 changes: 38 additions & 1 deletion src/material/legacy-radio/radio.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {waitForAsync, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/forms';
import {Component, DebugElement, ViewChild} from '@angular/core';
import {CommonModule} from '@angular/common';
import {By} from '@angular/platform-browser';
import {dispatchFakeEvent} from '@angular/cdk/testing/private';

Expand All @@ -10,7 +11,7 @@ import {MatLegacyRadioButton, MatLegacyRadioGroup, MatLegacyRadioModule} from '.
describe('MatRadio', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [MatLegacyRadioModule, FormsModule, ReactiveFormsModule],
imports: [MatLegacyRadioModule, FormsModule, ReactiveFormsModule, CommonModule],
declarations: [
DisableableRadioButton,
FocusableRadioButton,
Expand All @@ -23,6 +24,7 @@ describe('MatRadio', () => {
RadioButtonWithPredefinedTabindex,
RadioButtonWithPredefinedAriaAttributes,
RadiosInsidePreCheckedRadioGroup,
PreselectedRadioWithStaticValueAndNgIf,
],
});

Expand Down Expand Up @@ -910,6 +912,14 @@ describe('MatRadio', () => {
expect(groupInstance.selected).toBe(radioInstances[2]);
});
});

it('should preselect a radio button with a static value and an ngIf', () => {
const fixture = TestBed.createComponent(PreselectedRadioWithStaticValueAndNgIf);
fixture.detectChanges();

expect(fixture.componentInstance.preselectedGroup.value).toBe('b');
expect(fixture.componentInstance.preselectedRadio.checked).toBe(true);
});
});

describe('MatRadioDefaultOverrides', () => {
Expand Down Expand Up @@ -1120,3 +1130,30 @@ class RadioButtonWithColorBinding {}
aria-labelledby="something-else"></mat-radio-button>`,
})
class RadioButtonWithPredefinedAriaAttributes {}

@Component({
// Note that this is somewhat of a contrived template, but it is required to
// reproduce the issue. It was taken for a specific user report at #25831.
template: `
<ng-container *ngIf="true">
<mat-radio-group [formControl]="controls.predecessor">
<mat-radio-button value="predecessor"></mat-radio-button>
</mat-radio-group>
</ng-container>

<mat-radio-group [formControl]="controls.target" #preselectedGroup>
<mat-radio-button value="a"></mat-radio-button>
<mat-radio-button *ngIf="true" value="b" #preselectedRadio></mat-radio-button>
</mat-radio-group>
`,
})
class PreselectedRadioWithStaticValueAndNgIf {
@ViewChild('preselectedGroup', {read: MatLegacyRadioGroup}) preselectedGroup: MatLegacyRadioGroup;
@ViewChild('preselectedRadio', {read: MatLegacyRadioButton})
preselectedRadio: MatLegacyRadioButton;

controls = {
predecessor: new FormControl('predecessor'),
target: new FormControl('b'),
};
}
1 change: 1 addition & 0 deletions src/material/radio/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ ng_test_library(
deps = [
":radio",
"//src/cdk/testing/private",
"@npm//@angular/common",
"@npm//@angular/forms",
"@npm//@angular/platform-browser",
"@npm//@material/radio",
Expand Down
38 changes: 37 additions & 1 deletion src/material/radio/radio.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {waitForAsync, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/forms';
import {Component, DebugElement, ViewChild} from '@angular/core';
import {CommonModule} from '@angular/common';
import {By} from '@angular/platform-browser';
import {dispatchFakeEvent} from '../../cdk/testing/private';
import {
Expand All @@ -14,7 +15,7 @@ import {
describe('MDC-based MatRadio', () => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [MatRadioModule, FormsModule, ReactiveFormsModule],
imports: [MatRadioModule, FormsModule, ReactiveFormsModule, CommonModule],
declarations: [
DisableableRadioButton,
FocusableRadioButton,
Expand All @@ -27,6 +28,7 @@ describe('MDC-based MatRadio', () => {
RadioButtonWithPredefinedTabindex,
RadioButtonWithPredefinedAriaAttributes,
RadiosInsidePreCheckedRadioGroup,
PreselectedRadioWithStaticValueAndNgIf,
],
});

Expand Down Expand Up @@ -927,6 +929,14 @@ describe('MDC-based MatRadio', () => {
expect(groupInstance.selected).toBe(radioInstances[2]);
});
});

it('should preselect a radio button with a static value and an ngIf', () => {
const fixture = TestBed.createComponent(PreselectedRadioWithStaticValueAndNgIf);
fixture.detectChanges();

expect(fixture.componentInstance.preselectedGroup.value).toBe('b');
expect(fixture.componentInstance.preselectedRadio.checked).toBe(true);
});
});

describe('MatRadioDefaultOverrides', () => {
Expand Down Expand Up @@ -1138,3 +1148,29 @@ class RadioButtonWithColorBinding {}
aria-labelledby="something-else"></mat-radio-button>`,
})
class RadioButtonWithPredefinedAriaAttributes {}

@Component({
// Note that this is somewhat of a contrived template, but it is required to
// reproduce the issue. It was taken for a specific user report at #25831.
template: `
<ng-container *ngIf="true">
<mat-radio-group [formControl]="controls.predecessor">
<mat-radio-button value="predecessor"></mat-radio-button>
</mat-radio-group>
</ng-container>

<mat-radio-group [formControl]="controls.target" #preselectedGroup>
<mat-radio-button value="a"></mat-radio-button>
<mat-radio-button *ngIf="true" value="b" #preselectedRadio></mat-radio-button>
</mat-radio-group>
`,
})
class PreselectedRadioWithStaticValueAndNgIf {
@ViewChild('preselectedGroup', {read: MatRadioGroup}) preselectedGroup: MatRadioGroup;
@ViewChild('preselectedRadio', {read: MatRadioButton}) preselectedRadio: MatRadioButton;

controls = {
predecessor: new FormControl('predecessor'),
target: new FormControl('b'),
};
}
12 changes: 6 additions & 6 deletions src/material/radio/radio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -510,12 +510,6 @@ export abstract class _MatRadioButtonBase
if (tabIndex) {
this.tabIndex = coerceNumberProperty(tabIndex, 0);
}

this._removeUniqueSelectionListener = _radioDispatcher.listen((id: string, name: string) => {
if (id !== this.id && name === this.name) {
this.checked = false;
}
});
}

/** Focuses the radio button. */
Expand Down Expand Up @@ -550,6 +544,12 @@ export abstract class _MatRadioButtonBase
// Copy name from parent radio group
this.name = this.radioGroup.name;
}

this._removeUniqueSelectionListener = this._radioDispatcher.listen((id, name) => {
if (id !== this.id && name === this.name) {
this.checked = false;
}
});
}

ngDoCheck(): void {
Expand Down