From e468a2113923e66f141914363a9202a594ee97a3 Mon Sep 17 00:00:00 2001 From: Adam Bradley Date: Sat, 13 Feb 2016 01:35:38 -0600 Subject: [PATCH] fix(checkbox): use value accessor provider Remove the value property and always recommend ngModel or ngControl. Closes #5353 --- ionic/components/checkbox/checkbox.ts | 110 ++++++++---------- ionic/components/checkbox/test/basic/index.ts | 11 ++ .../components/checkbox/test/basic/main.html | 24 ++-- ionic/components/toggle/test/basic/index.ts | 4 +- ionic/components/toggle/test/basic/main.html | 2 +- ionic/components/toggle/toggle.ts | 22 ++-- 6 files changed, 87 insertions(+), 86 deletions(-) diff --git a/ionic/components/checkbox/checkbox.ts b/ionic/components/checkbox/checkbox.ts index 7c877254dbe..c3d74843f10 100644 --- a/ionic/components/checkbox/checkbox.ts +++ b/ionic/components/checkbox/checkbox.ts @@ -1,16 +1,21 @@ -import {Component, Optional, Input, HostListener} from 'angular2/core'; -import {NgControl} from 'angular2/common'; +import {Component, Optional, Input, HostListener, Provider, forwardRef, Injector} from 'angular2/core'; +import {NgControl, NG_VALUE_ACCESSOR} from 'angular2/common'; import {Form} from '../../util/form'; import {Item} from '../item/item'; import {isTrueProperty} from '../../util/util'; +const CHECKBOX_VALUE_ACCESSOR = new Provider( + NG_VALUE_ACCESSOR, {useExisting: forwardRef(() => Checkbox), multi: true}); + + /** * The checkbox is no different than the HTML checkbox input, except * it's styled accordingly to the the platform and design mode, such * as iOS or Material Design. * - * See the [Angular 2 Docs](https://angular.io/docs/js/latest/api/core/Form-interface.html) for more info on forms and input. + * See the [Angular 2 Docs](https://angular.io/docs/ts/latest/guide/forms.html) + * for more info on forms and inputs. * * * @usage @@ -20,17 +25,17 @@ import {isTrueProperty} from '../../util/util'; * * * Pepperoni - * + * * * * * Sausage - * + * * * * * Mushrooms - * + * * * * @@ -53,34 +58,27 @@ import {isTrueProperty} from '../../util/util'; '', host: { '[class.checkbox-disabled]': '_disabled' - } + }, + providers: [CHECKBOX_VALUE_ACCESSOR] }) export class Checkbox { private _checked: any = false; private _disabled: any = false; private _labelId: string; + private _fn: Function; /** * @private */ id: string; - /** - * @input {string} the value of the checkbox component - */ - @Input() value: string = ''; - constructor( private _form: Form, @Optional() private _item: Item, - @Optional() ngControl: NgControl + private _injector: Injector ) { _form.register(this); - if (ngControl) { - ngControl.valueAccessor = this; - } - if (_item) { this.id = 'chk-' + _item.registerInput('checkbox'); this._labelId = 'lbl-' + _item.id; @@ -90,10 +88,13 @@ export class Checkbox { /** * @private - * Toggle the checked state of the checkbox. Calls onChange to pass the updated checked state to the model (Control). */ - toggle() { - this.checked = !this.checked; + @HostListener('click', ['$event']) + private _click(ev) { + console.debug('checkbox, checked'); + ev.preventDefault(); + ev.stopPropagation(); + this.onChange(!this._checked); } /** @@ -105,79 +106,64 @@ export class Checkbox { } set checked(val) { - if (!this._disabled) { - this._checked = isTrueProperty(val); - this.onChange(this._checked); - this._item && this._item.setCssClass('item-checkbox-checked', this._checked); - } + this._setChecked(isTrueProperty(val)); + this.onChange(this._checked); } /** - * @input {boolean} whether or not the checkbox is disabled or not. + * @private */ - @Input() - get disabled() { - return this._disabled; - } - - set disabled(val) { - this._disabled = isTrueProperty(val); - this._item && this._item.setCssClass('item-checkbox-disabled', this._disabled); + private _setChecked(isChecked: boolean) { + this._checked = isChecked; + this._item && this._item.setCssClass('item-checkbox-checked', isChecked); } /** * @private */ - @HostListener('click', ['$event']) - private _click(ev) { - console.debug('checkbox, checked', this.value); - ev.preventDefault(); - ev.stopPropagation(); - this.toggle(); + writeValue(val: any) { + this._setChecked( isTrueProperty(val) ); } /** * @private - * Angular2 Forms API method called by the model (Control) on change to update - * the checked value. - * https://github.com/angular/angular/blob/master/modules/angular2/src/forms/directives/shared.ts#L34 */ - writeValue(val) { - if (val !== null) { - this.checked = val; - } + registerOnChange(fn: Function): void { + this._fn = fn; + this.onChange = (isChecked: boolean) => { + console.debug('checkbox, onChange', isChecked); + fn(isChecked); + this._setChecked(isChecked); + }; } /** * @private */ - onChange(val) { - // TODO: figure the whys and the becauses - } + registerOnTouched(fn) { this.onTouched = fn; } /** - * @private + * @input {boolean} whether or not the checkbox is disabled or not. */ - onTouched(val) { - // TODO: figure the whys and the becauses + @Input() + get disabled(): any { + return this._disabled; + } + + set disabled(val: any) { + this._disabled = isTrueProperty(val); + this._item && this._item.setCssClass('item-checkbox-disabled', this._disabled); } /** * @private - * Angular2 Forms API method called by the view (NgControl) to register the - * onChange event handler that updates the model (Control). - * https://github.com/angular/angular/blob/master/modules/angular2/src/forms/directives/shared.ts#L27 - * @param {function} fn the onChange event handler. */ - registerOnChange(fn) { this.onChange = fn; } + onChange(_) {} /** * @private - * Angular2 Forms API method called by the the view (NgControl) to register - * the onTouched event handler that marks model (Control) as touched. - * @param {function} fn onTouched event handler. */ - registerOnTouched(fn) { this.onTouched = fn; } + onTouched() {} /** * @private diff --git a/ionic/components/checkbox/test/basic/index.ts b/ionic/components/checkbox/test/basic/index.ts index cbdcaac68fe..ec21c321817 100644 --- a/ionic/components/checkbox/test/basic/index.ts +++ b/ionic/components/checkbox/test/basic/index.ts @@ -16,6 +16,14 @@ import { templateUrl: 'main.html' }) class E2EApp { + fruitsForm: ControlGroup; + grapeDisabled: boolean; + grapeChecked: boolean; + kiwiModel: boolean; + strawberryModel: boolean; + standAloneChecked: boolean; + formResults: string; + constructor() { this.fruitsForm = new ControlGroup({ "appleCtrl": new Control(), @@ -27,6 +35,9 @@ class E2EApp { this.grapeDisabled = true; this.grapeChecked = true; this.standAloneChecked = true; + + this.kiwiModel = false; + this.strawberryModel = true; } toggleGrapeChecked() { diff --git a/ionic/components/checkbox/test/basic/main.html b/ionic/components/checkbox/test/basic/main.html index 618fad4b694..18815a33061 100644 --- a/ionic/components/checkbox/test/basic/main.html +++ b/ionic/components/checkbox/test/basic/main.html @@ -9,33 +9,33 @@ - Apple, value=apple, init checked - + Apple, ngControl + - Banana, init no checked/value attributes + Banana, ngControl - Cherry, value=cherry, init disabled - + Cherry, ngControl, disabled + - Grape, value=grape, init checked, disabled - + Grape, ngControl, checked, disabled + - secondary color - + Kiwi, NgModel false, Secondary color + - light color - + Strawberry, NgModel true + @@ -62,6 +62,8 @@ cherry.value: {{fruitsForm.controls.cherryCtrl.value}}
grape.dirty: {{fruitsForm.controls.grapeCtrl.dirty}}
grape.value: {{fruitsForm.controls.grapeCtrl.value}}
+ kiwiModel: {{kiwiModel}}
+ strawberryModel: {{strawberryModel}}

diff --git a/ionic/components/toggle/test/basic/index.ts b/ionic/components/toggle/test/basic/index.ts index aa9d73f3cdb..492db13db5a 100644 --- a/ionic/components/toggle/test/basic/index.ts +++ b/ionic/components/toggle/test/basic/index.ts @@ -17,6 +17,7 @@ import { class E2EApp { fruitsForm: ControlGroup; grapeDisabled: boolean; + grapeChecked: boolean; kiwiModel: boolean; strawberryModel: boolean; formResults: string; @@ -29,6 +30,7 @@ class E2EApp { "grapeCtrl": new Control(true) }); + this.grapeChecked = true; this.grapeDisabled = true; this.kiwiModel = false; @@ -36,7 +38,7 @@ class E2EApp { } toggleGrapeChecked() { - this.fruitsForm.controls['grapeCtrl'].updateValue( !this.fruitsForm.controls['grapeCtrl'].value ) + this.grapeChecked = !this.grapeChecked; } toggleGrapeDisabled() { diff --git a/ionic/components/toggle/test/basic/main.html b/ionic/components/toggle/test/basic/main.html index cd80d285337..5d537a89a27 100644 --- a/ionic/components/toggle/test/basic/main.html +++ b/ionic/components/toggle/test/basic/main.html @@ -24,7 +24,7 @@ Grape, ngControl, checked, disabled - + diff --git a/ionic/components/toggle/toggle.ts b/ionic/components/toggle/toggle.ts index 704cb52bc66..91ac230b9f8 100644 --- a/ionic/components/toggle/toggle.ts +++ b/ionic/components/toggle/toggle.ts @@ -20,7 +20,7 @@ const TOGGLE_VALUE_ACCESSOR = new Provider( * attribute. * * See the [Angular 2 Docs](https://angular.io/docs/ts/latest/guide/forms.html) - * for more info on forms and input. + * for more info on forms and inputs. * @property {boolean} [checked] - whether the toggle it toggled or not * @property {boolean} [disabled] - whether the toggle is disabled or not * @@ -36,7 +36,7 @@ const TOGGLE_VALUE_ACCESSOR = new Provider( * * * Sausage - * + * * * * @@ -180,6 +180,14 @@ export class Toggle implements ControlValueAccessor { this.onChange(this._checked); } + /** + * @private + */ + private _setChecked(isChecked: boolean) { + this._checked = isChecked; + this._item && this._item.setCssClass('item-toggle-checked', isChecked); + } + /** * @private */ @@ -202,10 +210,7 @@ export class Toggle implements ControlValueAccessor { /** * @private */ - private _setChecked(isChecked: boolean) { - this._checked = isChecked; - this._item && this._item.setCssClass('item-toggle-checked', isChecked); - } + registerOnTouched(fn) { this.onTouched = fn; } @Input() get disabled(): any { @@ -217,11 +222,6 @@ export class Toggle implements ControlValueAccessor { this._item && this._item.setCssClass('item-toggle-disabled', this._disabled); } - /** - * @private - */ - registerOnTouched(fn) { this.onTouched = fn; } - /** * @private */