Skip to content

Commit 5c47d56

Browse files
committed
fix(radio): update set disabled directly on MatRadioButton to trigger change detection
Fixes MatRadioButton.disabled setter to trigger change detection. MatRadioButton uses ChangeDetectionStrategy.OnPush, which works fine with disabled is bound in a template that uses <mat-radio-button>. However, if a parent directly accesses the MatRadioButton component instance (e.g., using ViewChild, as in the provided test case), there is otherwise no way for the parent to trigger change detection in the MatRadioButton due to the OnPush strategy. OnPush was added in 97a9bdc, and this same technique was added to some but not all setters. This commit also adds test coverage for directly setting disabled on MatRadioButton in general, which previously was only indirectly covered in the MatRadioGroup tests.
1 parent 54c0b00 commit 5c47d56

File tree

2 files changed

+50
-2
lines changed

2 files changed

+50
-2
lines changed

src/lib/radio/radio.spec.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
22
import {FormControl, FormsModule, NgModel, ReactiveFormsModule} from '@angular/forms';
3-
import {Component, DebugElement} from '@angular/core';
3+
import {Component, DebugElement, ViewChild} from '@angular/core';
44
import {By} from '@angular/platform-browser';
55
import {dispatchFakeEvent} from '@angular/cdk/testing';
66
import {defaultRippleAnimationConfig} from '@angular/material/core';
@@ -12,6 +12,7 @@ describe('MatRadio', () => {
1212
TestBed.configureTestingModule({
1313
imports: [MatRadioModule, FormsModule, ReactiveFormsModule],
1414
declarations: [
15+
DisableableRadioButton,
1516
FocusableRadioButton,
1617
RadiosInsideRadioGroup,
1718
RadioGroupWithNgModel,
@@ -515,6 +516,38 @@ describe('MatRadio', () => {
515516
});
516517
});
517518

519+
describe('disableable', () => {
520+
let fixture: ComponentFixture<DisableableRadioButton>;
521+
let radioInstance: MatRadioButton;
522+
let radioNativeElement: HTMLInputElement;
523+
let testComponent: DisableableRadioButton;
524+
525+
beforeEach(() => {
526+
fixture = TestBed.createComponent(DisableableRadioButton);
527+
fixture.detectChanges();
528+
529+
testComponent = fixture.debugElement.componentInstance;
530+
const radioDebugElement = fixture.debugElement.query(By.directive(MatRadioButton));
531+
radioInstance = radioDebugElement.injector.get<MatRadioButton>(MatRadioButton);
532+
radioNativeElement = radioDebugElement.nativeElement.querySelector('input');
533+
});
534+
535+
it('should toggle the disabled state', () => {
536+
expect(radioInstance.disabled).toBeFalsy();
537+
expect(radioNativeElement.disabled).toBeFalsy();
538+
539+
testComponent.disabled = true;
540+
fixture.detectChanges();
541+
expect(radioInstance.disabled).toBeTruthy();
542+
expect(radioNativeElement.disabled).toBeTruthy();
543+
544+
testComponent.disabled = false;
545+
fixture.detectChanges();
546+
expect(radioInstance.disabled).toBeFalsy();
547+
expect(radioNativeElement.disabled).toBeFalsy();
548+
});
549+
});
550+
518551
describe('as standalone', () => {
519552
let fixture: ComponentFixture<StandaloneRadioButtons>;
520553
let radioDebugElements: DebugElement[];
@@ -795,6 +828,17 @@ class RadioGroupWithNgModel {
795828
lastEvent: MatRadioChange;
796829
}
797830

831+
@Component({
832+
template: `<mat-radio-button>One</mat-radio-button>`
833+
})
834+
class DisableableRadioButton {
835+
@ViewChild(MatRadioButton) matRadioButton;
836+
837+
set disabled(value: boolean) {
838+
this.matRadioButton.disabled = value;
839+
}
840+
}
841+
798842
@Component({
799843
template: `
800844
<mat-radio-group [formControl]="formControl">

src/lib/radio/radio.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,11 @@ export class MatRadioButton extends _MatRadioButtonMixinBase
410410
return this._disabled || (this.radioGroup !== null && this.radioGroup.disabled);
411411
}
412412
set disabled(value: boolean) {
413-
this._disabled = coerceBooleanProperty(value);
413+
const newDisabledState = coerceBooleanProperty(value);
414+
if (this._disabled !== newDisabledState) {
415+
this._disabled = newDisabledState;
416+
this._changeDetector.markForCheck();
417+
}
414418
}
415419

416420
/** Whether the radio button is required. */

0 commit comments

Comments
 (0)