diff --git a/src/lib/radio/radio.spec.ts b/src/lib/radio/radio.spec.ts
index 5f2c67c86e2b..20dec0dddccb 100644
--- a/src/lib/radio/radio.spec.ts
+++ b/src/lib/radio/radio.spec.ts
@@ -229,7 +229,7 @@ describe('MdRadio', () => {
});
it('should not show ripples on disabled radio buttons', () => {
- radioInstances[0].disabled = true;
+ testComponent.isFirstDisabled = true;
fixture.detectChanges();
dispatchFakeEvent(radioLabelElements[0], 'mousedown');
@@ -238,7 +238,7 @@ describe('MdRadio', () => {
expect(radioNativeElements[0].querySelectorAll('.mat-ripple-element').length)
.toBe(0, 'Expected a disabled radio button to not show ripples');
- radioInstances[0].disabled = false;
+ testComponent.isFirstDisabled = false;
fixture.detectChanges();
dispatchFakeEvent(radioLabelElements[0], 'mousedown');
@@ -417,11 +417,13 @@ describe('MdRadio', () => {
it('should write to the radio button based on ngModel', fakeAsync(() => {
testComponent.modelValue = 'chocolate';
+
fixture.detectChanges();
tick();
fixture.detectChanges();
expect(innerRadios[1].nativeElement.checked).toBe(true);
+ expect(radioInstances[1].checked).toBe(true);
}));
it('should update the ngModel value when selecting a radio button', () => {
@@ -551,7 +553,7 @@ describe('MdRadio', () => {
it('should change aria-label attribute if property is changed at runtime', () => {
expect(fruitRadioNativeInputs[0].getAttribute('aria-label')).toBe('Banana');
- fruitRadioInstances[0].ariaLabel = 'Pineapple';
+ testComponent.ariaLabel = 'Pineapple';
fixture.detectChanges();
expect(fruitRadioNativeInputs[0].getAttribute('aria-label')).toBe('Pineapple');
@@ -568,7 +570,7 @@ describe('MdRadio', () => {
it('should change aria-labelledby attribute if property is changed at runtime', () => {
expect(fruitRadioNativeInputs[0].getAttribute('aria-labelledby')).toBe('xyz');
- fruitRadioInstances[0].ariaLabelledby = 'uvw';
+ testComponent.ariaLabelledby = 'uvw';
fixture.detectChanges();
expect(fruitRadioNativeInputs[0].getAttribute('aria-labelledby')).toBe('uvw');
@@ -593,7 +595,8 @@ describe('MdRadio', () => {
[labelPosition]="labelPos"
[value]="groupValue"
name="test-name">
- Charmander
+ Charmander
Squirtle
Bulbasaur
@@ -602,6 +605,7 @@ describe('MdRadio', () => {
class RadiosInsideRadioGroup {
labelPos: 'before' | 'after';
isGroupDisabled: boolean = false;
+ isFirstDisabled: boolean = false;
groupValue: string = null;
disableRipple: boolean = false;
}
@@ -618,12 +622,18 @@ class RadiosInsideRadioGroup {
Autumn
Baby Banana
-
+
Raspberry
`
})
-class StandaloneRadioButtons { }
+class StandaloneRadioButtons {
+ ariaLabel: string = 'Banana';
+ ariaLabelledby: string = 'xyz';
+}
@Component({
diff --git a/src/lib/radio/radio.ts b/src/lib/radio/radio.ts
index 803380aeed5e..bc099bec0996 100644
--- a/src/lib/radio/radio.ts
+++ b/src/lib/radio/radio.ts
@@ -1,5 +1,7 @@
import {
AfterContentInit,
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
Component,
ContentChildren,
Directive,
@@ -86,6 +88,12 @@ export class MdRadioGroup extends _MdRadioGroupMixinBase
/** Whether the `value` has been set to its initial value. */
private _isInitialized: boolean = false;
+ /** Whether the labels should appear after or before the radio-buttons. Defaults to 'after' */
+ private _labelPosition: 'before' | 'after' = 'after';
+
+ /** Whether the radio group is disabled. */
+ private _disabled: boolean = false;
+
/** The method to be called in order to update ngModel */
_controlValueAccessorChangeFn: (value: any) => void = (value) => {};
@@ -129,8 +137,17 @@ export class MdRadioGroup extends _MdRadioGroupMixinBase
this.labelPosition = (v == 'start') ? 'after' : 'before';
}
+
/** Whether the labels should appear after or before the radio-buttons. Defaults to 'after' */
- @Input() labelPosition: 'before' | 'after' = 'after';
+ @Input()
+ get labelPosition() {
+ return this._labelPosition;
+ }
+
+ set labelPosition(v) {
+ this._labelPosition = (v == 'before') ? 'before' : 'after';
+ this._markRadiosForCheck();
+ }
/** Value of the radio button. */
@Input()
@@ -160,6 +177,18 @@ export class MdRadioGroup extends _MdRadioGroupMixinBase
this._checkSelectedRadioButton();
}
+ /** Whether the radio group is diabled */
+ @Input()
+ get disabled() { return this._disabled; }
+ set disabled(value) {
+ this._disabled = value;
+ this._markRadiosForCheck();
+ }
+
+ constructor(private _changeDetector: ChangeDetectorRef) {
+ super();
+ }
+
/**
* Initialize properties once content children are available.
* This allows us to propagate relevant attributes to associated buttons.
@@ -215,12 +244,19 @@ export class MdRadioGroup extends _MdRadioGroupMixinBase
}
}
+ _markRadiosForCheck() {
+ if (this._radios) {
+ this._radios.forEach(radio => radio._markForCheck());
+ }
+ }
+
/**
* Sets the model value. Implemented as part of ControlValueAccessor.
* @param value
*/
writeValue(value: any) {
this.value = value;
+ this._changeDetector.markForCheck();
}
/**
@@ -247,6 +283,7 @@ export class MdRadioGroup extends _MdRadioGroupMixinBase
*/
setDisabledState(isDisabled: boolean) {
this.disabled = isDisabled;
+ this._changeDetector.markForCheck();
}
}
@@ -264,7 +301,8 @@ export class MdRadioGroup extends _MdRadioGroupMixinBase
'[class.mat-radio-checked]': 'checked',
'[class.mat-radio-disabled]': 'disabled',
'[attr.id]': 'id',
- }
+ },
+ changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MdRadioButton implements OnInit, AfterViewInit, OnDestroy {
@@ -307,6 +345,7 @@ export class MdRadioButton implements OnInit, AfterViewInit, OnDestroy {
// Notify all radio buttons with the same name to un-check.
this._radioDispatcher.notify(this.id, this.name);
}
+ this._changeDetector.markForCheck();
}
}
@@ -328,7 +367,6 @@ export class MdRadioButton implements OnInit, AfterViewInit, OnDestroy {
this.radioGroup.selected = this;
}
}
-
}
}
@@ -364,7 +402,6 @@ export class MdRadioButton implements OnInit, AfterViewInit, OnDestroy {
get disabled(): boolean {
return this._disabled || (this.radioGroup != null && this.radioGroup.disabled);
}
-
set disabled(value: boolean) {
this._disabled = coerceBooleanProperty(value);
}
@@ -408,6 +445,7 @@ export class MdRadioButton implements OnInit, AfterViewInit, OnDestroy {
constructor(@Optional() radioGroup: MdRadioGroup,
private _elementRef: ElementRef,
private _renderer: Renderer2,
+ private _changeDetector: ChangeDetectorRef,
private _focusOriginMonitor: FocusOriginMonitor,
private _radioDispatcher: UniqueSelectionDispatcher) {
// Assertions. Ideally these should be stripped out by the compiler.
@@ -427,6 +465,17 @@ export class MdRadioButton implements OnInit, AfterViewInit, OnDestroy {
this._focusOriginMonitor.focusVia(this._inputElement.nativeElement, this._renderer, 'keyboard');
}
+ /**
+ * Marks the radio button as needing checking for change detection.
+ * This method is exposed because the parent radio group will directly
+ * update bound properties of the radio button.
+ */
+ _markForCheck() {
+ // When group value changes, the button will not be notified. Use `markForCheck` to explicit
+ // update radio button's status
+ this._changeDetector.markForCheck();
+ }
+
ngOnInit() {
if (this.radioGroup) {
// If the radio is inside a radio group, determine if it should be checked