diff --git a/src/demo-app/radio/radio-demo.html b/src/demo-app/radio/radio-demo.html
index 6d0b02e458d..043690f4b7e 100644
--- a/src/demo-app/radio/radio-demo.html
+++ b/src/demo-app/radio/radio-demo.html
@@ -21,10 +21,20 @@
Disable buttons
+
+ isRequired: {{isRequired}}
+
+
Align end
-
+
Option 1
Option 2
Option 3
diff --git a/src/demo-app/radio/radio-demo.ts b/src/demo-app/radio/radio-demo.ts
index c967c1914ea..9f586b7cf38 100644
--- a/src/demo-app/radio/radio-demo.ts
+++ b/src/demo-app/radio/radio-demo.ts
@@ -8,8 +8,9 @@ import {Component} from '@angular/core';
styleUrls: ['radio-demo.css'],
})
export class RadioDemo {
- isDisabled: boolean = false;
isAlignEnd: boolean = false;
+ isDisabled: boolean = false;
+ isRequired: boolean = false;
favoriteSeason: string = 'Autumn';
seasonOptions = [
'Winter',
diff --git a/src/lib/radio/radio.html b/src/lib/radio/radio.html
index 234a1728239..2b455fd4151 100644
--- a/src/lib/radio/radio.html
+++ b/src/lib/radio/radio.html
@@ -16,6 +16,7 @@
[checked]="checked"
[disabled]="disabled"
[name]="name"
+ [required]="required"
[attr.aria-label]="ariaLabel"
[attr.aria-labelledby]="ariaLabelledby"
(change)="_onInputChange($event)"
diff --git a/src/lib/radio/radio.spec.ts b/src/lib/radio/radio.spec.ts
index 281594f1aba..c06f760be31 100644
--- a/src/lib/radio/radio.spec.ts
+++ b/src/lib/radio/radio.spec.ts
@@ -62,7 +62,7 @@ describe('MdRadio', () => {
it('should set individual radio names based on the group name', () => {
expect(groupInstance.name).toBeTruthy();
- for (let radio of radioInstances) {
+ for (const radio of radioInstances) {
expect(radio.name).toBe(groupInstance.name);
}
});
@@ -92,14 +92,14 @@ describe('MdRadio', () => {
testComponent.labelPos = 'before';
fixture.detectChanges();
- for (let radio of radioInstances) {
+ for (const radio of radioInstances) {
expect(radio.labelPosition).toBe('before');
}
testComponent.labelPos = 'after';
fixture.detectChanges();
- for (let radio of radioInstances) {
+ for (const radio of radioInstances) {
expect(radio.labelPosition).toBe('after');
}
});
@@ -108,11 +108,20 @@ describe('MdRadio', () => {
testComponent.isGroupDisabled = true;
fixture.detectChanges();
- for (let radio of radioInstances) {
+ for (const radio of radioInstances) {
expect(radio.disabled).toBe(true);
}
});
+ it('should set required to each radio button when the group is required', () => {
+ testComponent.isGroupRequired = true;
+ fixture.detectChanges();
+
+ for (const radio of radioInstances) {
+ expect(radio.required).toBe(true);
+ }
+ });
+
it('should update the group value when one of the radios changes', () => {
expect(groupInstance.value).toBeFalsy();
@@ -155,7 +164,7 @@ describe('MdRadio', () => {
it('should emit a change event from radio buttons', () => {
expect(radioInstances[0].checked).toBe(false);
- let spies = radioInstances
+ const spies = radioInstances
.map((radio, index) => jasmine.createSpy(`onChangeSpy ${index} for ${radio.name}`));
spies.forEach((spy, index) => radioInstances[index].change.subscribe(spy));
@@ -178,7 +187,7 @@ describe('MdRadio', () => {
programmatically`, () => {
expect(groupInstance.value).toBeFalsy();
- let changeSpy = jasmine.createSpy('radio-group change listener');
+ const changeSpy = jasmine.createSpy('radio-group change listener');
groupInstance.change.subscribe(changeSpy);
radioLabelElements[0].click();
@@ -265,7 +274,7 @@ describe('MdRadio', () => {
testComponent.disableRipple = true;
fixture.detectChanges();
- for (let radioLabel of radioLabelElements) {
+ for (const radioLabel of radioLabelElements) {
dispatchFakeEvent(radioLabel, 'mousedown');
dispatchFakeEvent(radioLabel, 'mouseup');
@@ -275,7 +284,7 @@ describe('MdRadio', () => {
testComponent.disableRipple = false;
fixture.detectChanges();
- for (let radioLabel of radioLabelElements) {
+ for (const radioLabel of radioLabelElements) {
dispatchFakeEvent(radioLabel, 'mousedown');
dispatchFakeEvent(radioLabel, 'mouseup');
@@ -285,7 +294,7 @@ describe('MdRadio', () => {
it(`should update the group's selected radio to null when unchecking that radio
programmatically`, () => {
- let changeSpy = jasmine.createSpy('radio-group change listener');
+ const changeSpy = jasmine.createSpy('radio-group change listener');
groupInstance.change.subscribe(changeSpy);
radioInstances[0].checked = true;
@@ -305,7 +314,7 @@ describe('MdRadio', () => {
});
it('should not fire a change event from the group when a radio checked state changes', () => {
- let changeSpy = jasmine.createSpy('radio-group change listener');
+ const changeSpy = jasmine.createSpy('radio-group change listener');
groupInstance.change.subscribe(changeSpy);
radioInstances[0].checked = true;
@@ -324,7 +333,7 @@ describe('MdRadio', () => {
});
it(`should update checked status if changed value to radio group's value`, () => {
- let changeSpy = jasmine.createSpy('radio-group change listener');
+ const changeSpy = jasmine.createSpy('radio-group change listener');
groupInstance.change.subscribe(changeSpy);
groupInstance.value = 'apple';
@@ -403,25 +412,25 @@ describe('MdRadio', () => {
it('should set individual radio names based on the group name', () => {
expect(groupInstance.name).toBeTruthy();
- for (let radio of radioInstances) {
+ for (const radio of radioInstances) {
expect(radio.name).toBe(groupInstance.name);
}
groupInstance.name = 'new name';
- for (let radio of radioInstances) {
+ for (const radio of radioInstances) {
expect(radio.name).toBe(groupInstance.name);
}
});
it('should check the corresponding radio button on group value change', () => {
expect(groupInstance.value).toBeFalsy();
- for (let radio of radioInstances) {
+ for (const radio of radioInstances) {
expect(radio.checked).toBeFalsy();
}
groupInstance.value = 'vanilla';
- for (let radio of radioInstances) {
+ for (const radio of radioInstances) {
expect(radio.checked).toBe(groupInstance.value === radio.value);
}
expect(groupInstance.selected!.value).toBe(groupInstance.value);
@@ -539,12 +548,12 @@ describe('MdRadio', () => {
.filter(debugEl => debugEl.componentInstance.name == 'fruit')
.map(debugEl => debugEl.componentInstance);
- let fruitRadioNativeElements = radioDebugElements
+ const fruitRadioNativeElements = radioDebugElements
.filter(debugEl => debugEl.componentInstance.name == 'fruit')
.map(debugEl => debugEl.nativeElement);
fruitRadioNativeInputs = [];
- for (let element of fruitRadioNativeElements) {
+ for (const element of fruitRadioNativeElements) {
fruitRadioNativeInputs.push( element.querySelector('input'));
}
});
@@ -579,6 +588,14 @@ describe('MdRadio', () => {
expect(weatherRadioInstances[2].checked).toBe(true);
});
+ it('should add required attribute to the underlying input element if defined', () => {
+ const radioInstance = seasonRadioInstances[0];
+ radioInstance.required = true;
+ fixture.detectChanges();
+
+ expect(radioInstance.required).toBe(true);
+ });
+
it('should add aria-label attribute to the underlying input element if defined', () => {
expect(fruitRadioNativeInputs[0].getAttribute('aria-label')).toBe('Banana');
});
@@ -630,6 +647,7 @@ describe('MdRadio', () => {
template: `
{
})
class RadiosInsideRadioGroup {
labelPos: 'before' | 'after';
- isGroupDisabled: boolean = false;
isFirstDisabled: boolean = false;
+ isGroupDisabled: boolean = false;
+ isGroupRequired: boolean = false;
groupValue: string | null = null;
disableRipple: boolean = false;
color: string | null;
diff --git a/src/lib/radio/radio.ts b/src/lib/radio/radio.ts
index b6d9cb60898..e2287764635 100644
--- a/src/lib/radio/radio.ts
+++ b/src/lib/radio/radio.ts
@@ -105,6 +105,9 @@ export class MdRadioGroup extends _MdRadioGroupMixinBase
/** Whether the radio group is disabled. */
private _disabled: boolean = false;
+ /** Whether the radio group is required. */
+ private _required: boolean = false;
+
/** The method to be called in order to update ngModel */
_controlValueAccessorChangeFn: (value: any) => void = () => {};
@@ -189,12 +192,20 @@ export class MdRadioGroup extends _MdRadioGroupMixinBase
/** Whether the radio group is disabled */
@Input()
- get disabled() { return this._disabled; }
+ get disabled(): boolean { return this._disabled; }
set disabled(value) {
this._disabled = coerceBooleanProperty(value);
this._markRadiosForCheck();
}
+ /** Whether the radio group is required */
+ @Input()
+ get required(): boolean { return this._required; }
+ set required(value: boolean) {
+ this._required = coerceBooleanProperty(value);
+ this._markRadiosForCheck();
+ }
+
constructor(private _changeDetector: ChangeDetectorRef) {
super();
}
@@ -231,7 +242,7 @@ export class MdRadioGroup extends _MdRadioGroupMixinBase
/** Updates the `selected` radio button from the internal _value state. */
private _updateSelectedRadioFromValue(): void {
// If the value already matches the selected radio, do nothing.
- let isAlreadySelected = this._selected != null && this._selected.value == this._value;
+ const isAlreadySelected = this._selected != null && this._selected.value == this._value;
if (this._radios != null && !isAlreadySelected) {
this._selected = null;
@@ -247,7 +258,7 @@ export class MdRadioGroup extends _MdRadioGroupMixinBase
/** Dispatch change event with current selection and group value. */
_emitChangeEvent(): void {
if (this._isInitialized) {
- let event = new MdRadioChange();
+ const event = new MdRadioChange();
event.source = this._selected;
event.value = this._value;
this.change.emit(event);
@@ -424,6 +435,15 @@ export class MdRadioButton extends _MdRadioButtonMixinBase
this._disabled = coerceBooleanProperty(value);
}
+ /** Whether the radio button is required. */
+ @Input()
+ get required(): boolean {
+ return this._required || (this.radioGroup && this.radioGroup.required);
+ }
+ set required(value: boolean) {
+ this._required = coerceBooleanProperty(value);
+ }
+
/**
* Event emitted when the checked state of this radio button changes.
* Change events are only emitted when the value changes due to user interaction with
@@ -443,6 +463,9 @@ export class MdRadioButton extends _MdRadioButtonMixinBase
/** Whether this radio is disabled. */
private _disabled: boolean;
+ /** Whether this radio is required. */
+ private _required: boolean;
+
/** Value assigned to this radio.*/
private _value: any = null;
@@ -516,7 +539,7 @@ export class MdRadioButton extends _MdRadioButtonMixinBase
/** Dispatch change event with current value. */
private _emitChangeEvent(): void {
- let event = new MdRadioChange();
+ const event = new MdRadioChange();
event.source = this;
event.value = this._value;
this.change.emit(event);
@@ -547,7 +570,7 @@ export class MdRadioButton extends _MdRadioButtonMixinBase
// emit its event object to the `change` output.
event.stopPropagation();
- let groupValueChanged = this.radioGroup && this.value != this.radioGroup.value;
+ const groupValueChanged = this.radioGroup && this.value != this.radioGroup.value;
this.checked = true;
this._emitChangeEvent();