Skip to content

Commit 7c79a18

Browse files
authored
Merge pull request #209 from mseemann/fix205
wip: proposal solution
2 parents 7010ac5 + 111bbdb commit 7c79a18

File tree

4 files changed

+111
-16
lines changed

4 files changed

+111
-16
lines changed

src/demo-app/app/reactiveforms/reactiveform.component.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,3 +137,18 @@ <h4>Reactive Forms Example</h4>
137137
</pre>
138138
<a href="https://gist.github.com/mseemann/39d50d07a191be1df2c2d8f5ea244f7d" target="gist_angular2-mdl">Complete SourceCode</a>
139139
<br/>
140+
141+
<div>
142+
GroupTest:
143+
<form [formGroup]="testForm">
144+
<div formGroupName="group1" mdl-radio-group>
145+
<mdl-radio formControlName="type" value="type1"></mdl-radio>
146+
<mdl-radio formControlName="type" value="type2"></mdl-radio>
147+
</div>
148+
<div formGroupName="group2">
149+
<mdl-radio formControlName="type" value="type1"></mdl-radio>
150+
<mdl-radio formControlName="type" value="type2"></mdl-radio>
151+
</div>
152+
</form>
153+
<br/>
154+
</div>

src/demo-app/app/reactiveforms/reactiveform.component.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export class ReactiveFormsDemo extends AbstractDemoComponent implements OnInit {
4040
public breakfast = new FormControl('Continental');
4141
public toDrink = new FormControl('Tea');
4242

43+
public testForm: FormGroup;
4344

4445
constructor(router: Router, route: ActivatedRoute, titleService: Title, private fb: FormBuilder) {
4546
super(router, route, titleService);
@@ -64,6 +65,16 @@ export class ReactiveFormsDemo extends AbstractDemoComponent implements OnInit {
6465
.subscribe((formValues) => {
6566
console.log(`Model Driven Form valid: ${this.form.valid} value:`, JSON.stringify(formValues));
6667
});
68+
69+
// testform radio buttons inside groups
70+
this.testForm = new FormGroup({
71+
group1: new FormGroup({
72+
type: new FormControl('')
73+
}),
74+
group2: new FormGroup({
75+
type: new FormControl('')
76+
})
77+
});
6778
}
6879

6980
public onSubmit() {

src/lib/components/radio/mdl-radio.component.spec.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ describe('Component: MdlRadio', () => {
1010
beforeEach(async(() => {
1111
TestBed.configureTestingModule({
1212
imports: [ MdlRadioModule.forRoot(), FormsModule, ReactiveFormsModule ],
13-
declarations: [ MdlTestRadioComponent ],
13+
declarations: [ MdlTestRadioComponent, MdlTestUseSameRadioInGroupsComponent ],
1414
});
1515
}));
1616

@@ -161,6 +161,29 @@ describe('Component: MdlRadio', () => {
161161

162162
}));
163163

164+
165+
it('should be possible to use the same radio buttons in different groups', () => {
166+
let fixture = TestBed.createComponent(MdlTestUseSameRadioInGroupsComponent);
167+
fixture.detectChanges();
168+
169+
let g1t1Elem = fixture.debugElement.query(By.css('#g1t1')).nativeElement;
170+
let g1t2Elem = fixture.debugElement.query(By.css('#g1t2')).nativeElement;
171+
let g2t1Elem = fixture.debugElement.query(By.css('#g2t1')).nativeElement;
172+
173+
g1t1Elem.click();
174+
fixture.detectChanges();
175+
176+
expect(g1t1Elem.classList.contains('is-checked')).toBe(true, 'the clicked one should be selected');
177+
expect(g2t1Elem.classList.contains('is-checked')).toBe(false, 'the not clicked one should not be selected');
178+
179+
g1t2Elem.click();
180+
fixture.detectChanges();
181+
182+
expect(g1t1Elem.classList.contains('is-checked')).toBe(false, 'the not clicked one should not be selected');
183+
expect(g2t1Elem.classList.contains('is-checked')).toBe(false, 'the not clicked one should not be selected');
184+
185+
186+
});
164187
});
165188

166189

@@ -192,3 +215,36 @@ class MdlTestRadioComponent implements OnInit {
192215
}
193216

194217

218+
@Component({
219+
selector: 'test-radio',
220+
template: `
221+
<form [formGroup]="testForm">
222+
<div formGroupName="group1" mdl-radio-group>
223+
<mdl-radio formControlName="type" value="type1" id="g1t1"></mdl-radio>
224+
<mdl-radio formControlName="type" value="type2" id="g1t2"></mdl-radio>
225+
</div>
226+
<div formGroupName="group2">
227+
<mdl-radio formControlName="type" value="type1" id="g2t1"></mdl-radio>
228+
<mdl-radio formControlName="type" value="type2" id="g2t2"></mdl-radio>
229+
</div>
230+
</form>
231+
`
232+
})
233+
class MdlTestUseSameRadioInGroupsComponent implements OnInit {
234+
235+
public testForm: FormGroup;
236+
237+
constructor(private fb: FormBuilder) {}
238+
239+
public ngOnInit() {
240+
this.testForm = new FormGroup({
241+
group1: new FormGroup({
242+
type: new FormControl('')
243+
}),
244+
group2: new FormGroup({
245+
type: new FormControl('')
246+
})
247+
});
248+
}
249+
250+
}

src/lib/components/radio/mdl-radio.component.ts

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,19 @@ import {
1111
Injectable,
1212
OnDestroy,
1313
ViewEncapsulation,
14-
ModuleWithProviders
14+
ModuleWithProviders,
15+
Optional
1516
} from '@angular/core';
1617
import {
1718
NG_VALUE_ACCESSOR,
1819
ControlValueAccessor,
19-
FormsModule
20+
FormsModule,
21+
FormGroupName
2022
} from '@angular/forms';
2123
import { CommonModule } from '@angular/common';
2224
import { BooleanProperty } from '../common/boolean-property';
2325

26+
2427
const noop = () => {};
2528
const IS_FOCUSED = 'is-focused';
2629

@@ -31,22 +34,30 @@ const IS_FOCUSED = 'is-focused';
3134
@Injectable()
3235
export class MdlRadioGroupRegisty {
3336

34-
private radioComponents: any[] = [];
37+
private defaultFormGroup = 'defaultFromGroup';
38+
private radioComponents: {radio: MdlRadioComponent, group: FormGroupName | string}[] = [];
3539

36-
public add(radioComponent: MdlRadioComponent) {
37-
this.radioComponents.push(radioComponent);
40+
public add(radioComponent: MdlRadioComponent, formGroupName: FormGroupName) {
41+
this.radioComponents.push({
42+
radio: radioComponent,
43+
group: formGroupName || this.defaultFormGroup
44+
});
3845
}
3946

4047
public remove(radioComponent: MdlRadioComponent) {
41-
this.radioComponents.slice(this.radioComponents.indexOf(radioComponent), 1);
48+
this.radioComponents = this.radioComponents.filter( (radioComponentInArray) => {
49+
return (radioComponentInArray.radio !== radioComponent);
50+
});
4251
}
4352

44-
public select(radioComponent: MdlRadioComponent) {
45-
// unselect evenry radioComponent that is not the provided radiocomponent and has the same name
53+
public select(radioComponent: MdlRadioComponent, formGroupName: FormGroupName) {
54+
// unselect every radioComponent that is not the provided radiocomponent
55+
// and has the same name and is in teh same group.
56+
let groupToTest = formGroupName || this.defaultFormGroup;
4657
this.radioComponents.forEach( (component) => {
47-
if (component.name === radioComponent.name) {
48-
if (component !== radioComponent) {
49-
component.deselect(radioComponent.value);
58+
if (component.radio.name === radioComponent.name && component.group === groupToTest) {
59+
if (component.radio !== radioComponent) {
60+
component.radio.deselect(radioComponent.value);
5061
}
5162
}
5263
});
@@ -105,7 +116,8 @@ export class MdlRadioComponent implements ControlValueAccessor, OnInit, OnDestro
105116
constructor(
106117
private elementRef: ElementRef,
107118
private renderer: Renderer,
108-
private ragioGroupRegisty: MdlRadioGroupRegisty) {
119+
private ragioGroupRegisty: MdlRadioGroupRegisty,
120+
@Optional() private formGroupName: FormGroupName) {
109121
this.el = elementRef.nativeElement;
110122
}
111123

@@ -114,8 +126,9 @@ export class MdlRadioComponent implements ControlValueAccessor, OnInit, OnDestro
114126
// a radio group without name is useless.
115127
this.checkName();
116128
// register the radio button - this is the only chance to unselect the
117-
// radio button that is no longer active
118-
this.ragioGroupRegisty.add(this);
129+
// radio button that is no longer active - scope the radio button with it's group
130+
// if there is one.
131+
this.ragioGroupRegisty.add(this, this.formGroupName);
119132
}
120133

121134
public ngOnDestroy() {
@@ -137,7 +150,7 @@ export class MdlRadioComponent implements ControlValueAccessor, OnInit, OnDestro
137150
// wrap the callback, so that we can call select on the registry
138151
this.onChangeCallback = () => {
139152
fn(this.value);
140-
this.ragioGroupRegisty.select(this);
153+
this.ragioGroupRegisty.select(this, this.formGroupName);
141154
};
142155
}
143156

0 commit comments

Comments
 (0)