fix(forms): radio buttons with different names should not share state

Closes #7051
This commit is contained in:
Kara Erickson 2016-05-24 18:53:25 -07:00
parent 7a2ce7ff21
commit 6dc88f5b61
2 changed files with 58 additions and 21 deletions

View File

@ -43,11 +43,17 @@ export class RadioControlRegistry {
select(accessor: RadioControlValueAccessor) { select(accessor: RadioControlValueAccessor) {
this._accessors.forEach((c) => { this._accessors.forEach((c) => {
if (c[0].control.root === accessor._control.control.root && c[1] !== accessor) { if (this._isSameGroup(c, accessor) && c[1] !== accessor) {
c[1].fireUncheck(); c[1].fireUncheck();
} }
}); });
} }
private _isSameGroup(controlPair:[NgControl, RadioControlValueAccessor],
accessor: RadioControlValueAccessor) {
return controlPair[0].control.root === accessor._control.control.root &&
controlPair[1].name === accessor.name;
}
} }
/** /**

View File

@ -1203,44 +1203,75 @@ export function main() {
it("should support <type=radio>", it("should support <type=radio>",
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => { fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
var t = `<form> const t = `<form>
<input type="radio" name="food" ngControl="chicken" [(ngModel)]="data['chicken1']"> <input type="radio" name="food" ngControl="chicken" [(ngModel)]="data['chicken']">
<input type="radio" name="food" ngControl="fish" [(ngModel)]="data['fish1']"> <input type="radio" name="food" ngControl="fish" [(ngModel)]="data['fish']">
</form> <input type="radio" name="food" ngControl="beef" [(ngModel)]="data['beef']">
<form> <input type="radio" name="food" ngControl="pork" [(ngModel)]="data['pork']">
<input type="radio" name="food" ngControl="chicken" [(ngModel)]="data['chicken2']">
<input type="radio" name="food" ngControl="fish" [(ngModel)]="data['fish2']">
</form>`; </form>`;
let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8); const fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8);
tick(); tick();
fixture.debugElement.componentInstance.data = { fixture.debugElement.componentInstance.data = {
'chicken1': new RadioButtonState(false, 'chicken'), 'chicken': new RadioButtonState(false, 'chicken'),
'fish1': new RadioButtonState(true, 'fish'), 'fish': new RadioButtonState(true, 'fish'),
'beef': new RadioButtonState(false, 'beef'),
'chicken2': new RadioButtonState(false, 'chicken'), 'pork': new RadioButtonState(true, 'pork')
'fish2': new RadioButtonState(true, 'fish')
}; };
fixture.detectChanges(); fixture.detectChanges();
tick(); tick();
var input = fixture.debugElement.query(By.css("input")); const input = fixture.debugElement.query(By.css("input"));
expect(input.nativeElement.checked).toEqual(false); expect(input.nativeElement.checked).toEqual(false);
dispatchEvent(input.nativeElement, "change"); dispatchEvent(input.nativeElement, "change");
tick(); tick();
let data = fixture.debugElement.componentInstance.data; const data = fixture.debugElement.componentInstance.data;
expect(data['chicken1']).toEqual(new RadioButtonState(true, 'chicken')); expect(data['chicken']).toEqual(new RadioButtonState(true, 'chicken'));
expect(data['fish1']).toEqual(new RadioButtonState(false, 'fish')); expect(data['fish']).toEqual(new RadioButtonState(false, 'fish'));
expect(data['beef']).toEqual(new RadioButtonState(false, 'beef'));
expect(data['chicken2']).toEqual(new RadioButtonState(false, 'chicken')); expect(data['pork']).toEqual(new RadioButtonState(false, 'pork'));
expect(data['fish2']).toEqual(new RadioButtonState(true, 'fish'));
}))); })));
}); });
it("should support multiple named <type=radio> groups",
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
const t = `<form>
<input type="radio" name="food" ngControl="chicken" [(ngModel)]="data['chicken']">
<input type="radio" name="food" ngControl="fish" [(ngModel)]="data['fish']">
<input type="radio" name="drink" ngControl="cola" [(ngModel)]="data['cola']">
<input type="radio" name="drink" ngControl="sprite" [(ngModel)]="data['sprite']">
</form>`;
const fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8);
tick();
fixture.debugElement.componentInstance.data = {
'chicken': new RadioButtonState(false, 'chicken'),
'fish': new RadioButtonState(true, 'fish'),
'cola': new RadioButtonState(false, 'cola'),
'sprite': new RadioButtonState(true, 'sprite')
};
fixture.detectChanges();
tick();
const input = fixture.debugElement.query(By.css("input"));
expect(input.nativeElement.checked).toEqual(false);
dispatchEvent(input.nativeElement, "change");
tick();
const data = fixture.debugElement.componentInstance.data;
expect(data['chicken']).toEqual(new RadioButtonState(true, 'chicken'));
expect(data['fish']).toEqual(new RadioButtonState(false, 'fish'));
expect(data['cola']).toEqual(new RadioButtonState(false, 'cola'));
expect(data['sprite']).toEqual(new RadioButtonState(true, 'sprite'));
})));
describe("setting status classes", () => { describe("setting status classes", () => {
it("should work with single fields", it("should work with single fields",
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {