Skip to content

Commit c923f56

Browse files
robertmesserlejelbourn
authored andcommitted
fix(radio): model should update before change event is fired (#456)
closes #448
1 parent 5367a69 commit c923f56

File tree

2 files changed

+51
-12
lines changed

2 files changed

+51
-12
lines changed

src/components/radio/radio.spec.ts

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,50 @@ describe('MdRadio', () => {
297297
}));
298298
});
299299

300+
describe('group with ngModel and change event', () => {
301+
let fixture: ComponentFixture<RadioGroupWithNgModel>;
302+
let groupDebugElement: DebugElement;
303+
let groupNativeElement: HTMLElement;
304+
let radioDebugElements: DebugElement[];
305+
let radioNativeElements: HTMLElement[];
306+
let groupInstance: MdRadioGroup;
307+
let radioInstances: MdRadioButton[];
308+
let testComponent: RadioGroupWithNgModel;
309+
let groupNgControl: NgControl;
310+
311+
beforeEach(async(() => {
312+
builder.createAsync(RadioGroupWithNgModel).then(f => {
313+
fixture = f;
314+
315+
testComponent = fixture.componentInstance;
316+
317+
groupDebugElement = fixture.debugElement.query(By.directive(MdRadioGroup));
318+
groupNativeElement = groupDebugElement.nativeElement;
319+
groupInstance = groupDebugElement.injector.get(MdRadioGroup);
320+
groupNgControl = groupDebugElement.injector.get(NgControl);
321+
322+
radioDebugElements = fixture.debugElement.queryAll(By.directive(MdRadioButton));
323+
radioNativeElements = radioDebugElements.map(debugEl => debugEl.nativeElement);
324+
radioInstances = radioDebugElements.map(debugEl => debugEl.componentInstance);
325+
326+
fixture.detectChanges();
327+
328+
spyOn(testComponent, 'onChange');
329+
});
330+
}));
331+
332+
it('should update the model before firing change event', fakeAsync(() => {
333+
expect(testComponent.modelValue).toBeUndefined();
334+
335+
groupInstance.value = 'chocolate';
336+
fixture.detectChanges();
337+
338+
tick();
339+
expect(testComponent.modelValue).toBe('chocolate');
340+
expect(testComponent.onChange).toHaveBeenCalledWith('chocolate');
341+
}));
342+
});
343+
300344
describe('as standalone', () => {
301345
let fixture: ComponentFixture<StandaloneRadioButtons>;
302346
let radioDebugElements: DebugElement[];
@@ -388,7 +432,7 @@ class StandaloneRadioButtons { }
388432
@Component({
389433
directives: [MD_RADIO_DIRECTIVES, FORM_DIRECTIVES],
390434
template: `
391-
<md-radio-group [(ngModel)]="modelValue">
435+
<md-radio-group [(ngModel)]="modelValue" (change)="onChange(modelValue)">
392436
<md-radio-button *ngFor="let option of options" [value]="option.value">
393437
{{option.label}}
394438
</md-radio-button>
@@ -402,11 +446,11 @@ class RadioGroupWithNgModel {
402446
{label: 'Chocolate', value: 'chocolate'},
403447
{label: 'Strawberry', value: 'strawberry'},
404448
];
449+
onChange(value: string) {}
405450
}
406451

407452
// TODO(jelbourn): remove eveything below when Angular supports faking events.
408453

409-
410454
/**
411455
* Dispatches a focus change event from an element.
412456
* @param eventName Name of the event, either 'focus' or 'blur'.

src/components/radio/radio.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ export class MdRadioGroup implements AfterContentInit, ControlValueAccessor {
8080
/** Whether the `value` has been set to its initial value. */
8181
private _isInitialized: boolean = false;
8282

83-
/** Change event subscription set up by registerOnChange (ControlValueAccessor). */
84-
private _changeSubscription: {unsubscribe: () => any} = null;
83+
/** The method to be called in order to update ngModel */
84+
private _controlValueAccessorChangeFn: (value: any) => void = (value) => {};
8585

8686
/** onTouch function registered via registerOnTouch (ControlValueAccessor). */
8787
onTouched: () => any = () => {};
@@ -198,6 +198,7 @@ export class MdRadioGroup implements AfterContentInit, ControlValueAccessor {
198198
let event = new MdRadioChange();
199199
event.source = this._selected;
200200
event.value = this._value;
201+
this._controlValueAccessorChangeFn(event.value);
201202
this.change.emit(event);
202203
}
203204

@@ -213,14 +214,8 @@ export class MdRadioGroup implements AfterContentInit, ControlValueAccessor {
213214
* Implemented as part of ControlValueAccessor.
214215
* @internal
215216
*/
216-
registerOnChange(fn: any) {
217-
if (this._changeSubscription) {
218-
this._changeSubscription.unsubscribe();
219-
}
220-
221-
this._changeSubscription = this.change.subscribe((changeEvent: MdRadioChange) => {
222-
fn(changeEvent.value);
223-
});
217+
registerOnChange(fn: (value: any) => void) {
218+
this._controlValueAccessorChangeFn = fn;
224219
}
225220

226221
/**

0 commit comments

Comments
 (0)