Skip to content

Commit

Permalink
feat(checkbox): Added radiobutton support for reactive forms
Browse files Browse the repository at this point in the history
Closes #168
  • Loading branch information
edcarroll committed Jul 19, 2017
1 parent 1284a92 commit df06762
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 27 deletions.
21 changes: 11 additions & 10 deletions demo/src/app/pages/modules/checkbox/checkbox.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ const exampleRadioButtonTemplate = `
<div class="grouped fields">
<label>Radio Button Example</label>
<div class="field">
<sui-radio-button value="hello" [(ngModel)]="eRadio">Value: "hello"</sui-radio-button>
<sui-radio-button name="example" value="hello" [(ngModel)]="eRadio">Value: "hello"</sui-radio-button>
</div>
<div class="field">
<sui-radio-button value="world" [(ngModel)]="eRadio">Value: "world"</sui-radio-button>
<sui-radio-button name="example" value="world" [(ngModel)]="eRadio">Value: "world"</sui-radio-button>
</div>
<div class="field">
<sui-radio-button value="example" [(ngModel)]="eRadio">Value: "example"</sui-radio-button>
<sui-radio-button name="example" value="example" [(ngModel)]="eRadio">Value: "example"</sui-radio-button>
</div>
<div class="field">
<sui-radio-button [value]="{ example: 'object' }" [(ngModel)]="eRadio">
<sui-radio-button name="example" [value]="{ example: 'object' }" [(ngModel)]="eRadio">
Value: {{ '{' }} example: "object" }
</sui-radio-button>
</div>
Expand All @@ -62,12 +62,12 @@ const exampleStyledTemplate = `
<div class="grouped fields">
<label>Radio Button Style Examples</label>
<div class="field">
<sui-radio-button class="slider" value="a" [(ngModel)]="eStyledRadio">
<sui-radio-button class="slider" name="styled" value="a" [(ngModel)]="eStyledRadio">
Slider radio button
</sui-radio-button>
</div>
<div class="field">
<sui-radio-button class="toggle" value="b" [(ngModel)]="eStyledRadio">
<sui-radio-button class="toggle" name="styled" value="b" [(ngModel)]="eStyledRadio">
Toggle radio button
</sui-radio-button>
</div>
Expand Down Expand Up @@ -126,18 +126,19 @@ export class CheckboxPage {
{
name: "name",
type: "string",
description: "Sets the name on the internal <code>&lt;input&gt;</code> component."
description: "Sets the name on the internal <code>&lt;input&gt;</code> component.",
required: true
},
{
name: "value",
type: "T",
description: "Sets the value that selecting this radio button returns. Supports binding any object."
description: "Sets the value that selecting this radio button returns. Supports binding any object.",
required: true
},
{
name: "ngModel",
type: "T",
description: "Bind the radio button value to the value of the provided variable.",
required: true
description: "Bind the radio button value to the value of the provided variable."
},
{
name: "isDisabled",
Expand Down
4 changes: 2 additions & 2 deletions src/collections/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from "./message/message.module";
export * from "./pagination/pagination.module";
export * from "./message";
export * from "./pagination";
2 changes: 1 addition & 1 deletion src/misc/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "./util/util.module";
export * from "./util";
10 changes: 10 additions & 0 deletions src/misc/util/helpers/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ export const Util = {
}
return groups;
},
groupBy<T>(items:T[], field:keyof T):{ [name:string]:T[] } {
return items.reduce<{ [name:string]:T[] }>(
(groups, i) => {
const fieldValue = i[field].toString();
groups[fieldValue] = groups[fieldValue] || [];
groups[fieldValue].push(i);
return groups;
},
Object());
},
flatten<T>(items:T[][]):T[] {
return items.reduce((is, i) => is.concat(i), []);
}
Expand Down
13 changes: 8 additions & 5 deletions src/modules/checkbox/checkbox.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FormsModule } from "@angular/forms";
import { SuiCheckbox, SuiCheckboxValueAccessor } from "./components/checkbox";
import { SuiRadioButton, SuiRadioButtonValueAccessor } from "./components/radiobutton";
import { SuiRadio, SuiRadioValueAccessor } from "./components/radio";
import { SuiRadioManager } from "./directives/radio-manager";

@NgModule({
imports: [
Expand All @@ -12,14 +13,16 @@ import { SuiRadioButton, SuiRadioButtonValueAccessor } from "./components/radiob
declarations: [
SuiCheckbox,
SuiCheckboxValueAccessor,
SuiRadioButton,
SuiRadioButtonValueAccessor
SuiRadio,
SuiRadioValueAccessor,
SuiRadioManager
],
exports: [
SuiCheckbox,
SuiCheckboxValueAccessor,
SuiRadioButton,
SuiRadioButtonValueAccessor
SuiRadio,
SuiRadioValueAccessor,
SuiRadioManager
]
})
export class SuiCheckboxModule {}
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import {
Component, Directive, Input, Output, HostListener, HostBinding,
EventEmitter, ViewChild, ElementRef
EventEmitter, ViewChild, ElementRef, ContentChildren, AfterContentInit, QueryList
} from "@angular/core";
import { ICustomValueAccessorHost, customValueAccessorFactory, CustomValueAccessor } from "../../../misc/util";
import {
ICustomValueAccessorHost, customValueAccessorFactory, CustomValueAccessor,
Util
} from "../../../misc/util";
import { Subscription } from "rxjs/Subscription";

@Component({
selector: "sui-radio-button[ngModel]",
exportAs: "suiRadioButton",
selector: "sui-radio-button",
template: `
<input class="hidden"
type="checkbox"
Expand All @@ -21,7 +24,7 @@ import { ICustomValueAccessorHost, customValueAccessorFactory, CustomValueAccess
</label>
`
})
export class SuiRadioButton<T> implements ICustomValueAccessorHost<T> {
export class SuiRadio<T> implements ICustomValueAccessorHost<T> {
@HostBinding("class.ui")
@HostBinding("class.radio")
@HostBinding("class.checkbox")
Expand Down Expand Up @@ -113,10 +116,10 @@ export class SuiRadioButton<T> implements ICustomValueAccessorHost<T> {
"(currentValueChange)": "onChange($event)",
"(touched)": "onTouched()"
},
providers: [customValueAccessorFactory(SuiRadioButtonValueAccessor)]
providers: [customValueAccessorFactory(SuiRadioValueAccessor)]
})
export class SuiRadioButtonValueAccessor<T> extends CustomValueAccessor<T, SuiRadioButton<T>> {
constructor(host:SuiRadioButton<T>) {
export class SuiRadioValueAccessor<T> extends CustomValueAccessor<T, SuiRadio<T>> {
constructor(host:SuiRadio<T>) {
super(host);
}
}
57 changes: 57 additions & 0 deletions src/modules/checkbox/directives/radio-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Directive, AfterContentInit, ContentChildren, QueryList, ElementRef } from "@angular/core";
import { SuiRadio } from "../components/radio";
import { Subscription } from "rxjs/Subscription";
import { Util } from "../../../misc/util";

@Directive({
selector: "form:not([ngForm]):not([[ngForm]]),ngForm,[ngForm]"
})
export class SuiRadioManager<T> implements AfterContentInit {

public isNested:boolean;

@ContentChildren(SuiRadioManager, { descendants: true })
private _subManagers:QueryList<SuiRadioManager<T>>;

@ContentChildren(SuiRadio, { descendants: true })
private _renderedRadios:QueryList<SuiRadio<T>>;

private _radioSubs:Subscription[];

constructor(public element:ElementRef) {
this.isNested = false;
this._radioSubs = [];
}

public ngAfterContentInit():void {
this.updateNesting();
this._subManagers.changes.subscribe(() => this.updateNesting());

this.updateRadios();
this._renderedRadios.changes.subscribe(() => this.updateRadios());
}

private updateNesting():void {
this._subManagers
.filter(m => m !== this)
.forEach(m => m.isNested = true);
}

private updateRadios():void {
this._radioSubs.forEach(s => s.unsubscribe());
this._radioSubs = [];

const groups = Util.Array.groupBy(this._renderedRadios.toArray(), "name");
Object
.keys(groups)
.map(k => groups[k])
.forEach(g => g
.forEach(r => this._radioSubs
.push(r.onCurrentValueChange
.subscribe((v:T) => {
if (!this.isNested) {
g.forEach(radio => radio.writeValue(v));
}
}))));
}
}
4 changes: 3 additions & 1 deletion src/modules/checkbox/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export * from "./components/checkbox";
export * from "./components/radiobutton";
export * from "./components/radio";

export * from "./directives/radio-manager";

export * from "./checkbox.module";

0 comments on commit df06762

Please sign in to comment.