diff --git a/demo/src/app/pages/modules/checkbox/checkbox.page.ts b/demo/src/app/pages/modules/checkbox/checkbox.page.ts index 3f8378305..a2003ae16 100644 --- a/demo/src/app/pages/modules/checkbox/checkbox.page.ts +++ b/demo/src/app/pages/modules/checkbox/checkbox.page.ts @@ -28,16 +28,16 @@ const exampleRadioButtonTemplate = `
- Value: "hello" + Value: "hello"
- Value: "world" + Value: "world"
- Value: "example" + Value: "example"
- + Value: {{ '{' }} example: "object" }
@@ -62,12 +62,12 @@ const exampleStyledTemplate = `
- + Slider radio button
- + Toggle radio button
@@ -126,18 +126,19 @@ export class CheckboxPage { { name: "name", type: "string", - description: "Sets the name on the internal <input> component." + description: "Sets the name on the internal <input> 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", diff --git a/src/collections/index.ts b/src/collections/index.ts index 286751b8b..6a02976da 100644 --- a/src/collections/index.ts +++ b/src/collections/index.ts @@ -1,2 +1,2 @@ -export * from "./message/message.module"; -export * from "./pagination/pagination.module"; +export * from "./message"; +export * from "./pagination"; diff --git a/src/misc/index.ts b/src/misc/index.ts index c8af7d570..181e76f24 100644 --- a/src/misc/index.ts +++ b/src/misc/index.ts @@ -1 +1 @@ -export * from "./util/util.module"; +export * from "./util"; diff --git a/src/misc/util/helpers/util.ts b/src/misc/util/helpers/util.ts index 5efdeeac9..bf30e0ddf 100644 --- a/src/misc/util/helpers/util.ts +++ b/src/misc/util/helpers/util.ts @@ -42,6 +42,16 @@ export const Util = { } return groups; }, + groupBy(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(items:T[][]):T[] { return items.reduce((is, i) => is.concat(i), []); } diff --git a/src/modules/checkbox/checkbox.module.ts b/src/modules/checkbox/checkbox.module.ts index f85fa61bf..ced31139b 100644 --- a/src/modules/checkbox/checkbox.module.ts +++ b/src/modules/checkbox/checkbox.module.ts @@ -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: [ @@ -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 {} diff --git a/src/modules/checkbox/components/radiobutton.ts b/src/modules/checkbox/components/radio.ts similarity index 82% rename from src/modules/checkbox/components/radiobutton.ts rename to src/modules/checkbox/components/radio.ts index 58739c784..694f45d3d 100644 --- a/src/modules/checkbox/components/radiobutton.ts +++ b/src/modules/checkbox/components/radio.ts @@ -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: ` ` }) -export class SuiRadioButton implements ICustomValueAccessorHost { +export class SuiRadio implements ICustomValueAccessorHost { @HostBinding("class.ui") @HostBinding("class.radio") @HostBinding("class.checkbox") @@ -113,10 +116,10 @@ export class SuiRadioButton implements ICustomValueAccessorHost { "(currentValueChange)": "onChange($event)", "(touched)": "onTouched()" }, - providers: [customValueAccessorFactory(SuiRadioButtonValueAccessor)] + providers: [customValueAccessorFactory(SuiRadioValueAccessor)] }) -export class SuiRadioButtonValueAccessor extends CustomValueAccessor> { - constructor(host:SuiRadioButton) { +export class SuiRadioValueAccessor extends CustomValueAccessor> { + constructor(host:SuiRadio) { super(host); } } diff --git a/src/modules/checkbox/directives/radio-manager.ts b/src/modules/checkbox/directives/radio-manager.ts new file mode 100644 index 000000000..b0222cf6f --- /dev/null +++ b/src/modules/checkbox/directives/radio-manager.ts @@ -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 implements AfterContentInit { + + public isNested:boolean; + + @ContentChildren(SuiRadioManager, { descendants: true }) + private _subManagers:QueryList>; + + @ContentChildren(SuiRadio, { descendants: true }) + private _renderedRadios:QueryList>; + + 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)); + } + })))); + } +} diff --git a/src/modules/checkbox/index.ts b/src/modules/checkbox/index.ts index d97aae779..d61e87c5c 100644 --- a/src/modules/checkbox/index.ts +++ b/src/modules/checkbox/index.ts @@ -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";