diff --git a/angular/src/directives/control-value-accessors/boolean-value-accessor.ts b/angular/src/directives/control-value-accessors/boolean-value-accessor.ts index bed2e03b3b..8bc3f35801 100644 --- a/angular/src/directives/control-value-accessors/boolean-value-accessor.ts +++ b/angular/src/directives/control-value-accessors/boolean-value-accessor.ts @@ -1,7 +1,7 @@ import { Directive, ElementRef, HostListener } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { setIonicClasses } from './util/set-ionic-classes'; +import { ValueAccessor } from './value-accessor'; @Directive({ /* tslint:disable-next-line:directive-selector */ @@ -14,52 +14,14 @@ import { setIonicClasses } from './util/set-ionic-classes'; } ] }) -export class BooleanValueAccessor implements ControlValueAccessor { +export class BooleanValueAccessor extends ValueAccessor { - constructor(private element: ElementRef) { - this.onChange = () => {/**/}; - this.onTouched = () => {/**/}; - } - - onChange: (value: any) => void; - onTouched: () => void; - private lastValue: any; - - writeValue(value: any) { - this.element.nativeElement.checked = this.lastValue = value; - setIonicClasses(this.element); + constructor(el: ElementRef) { + super(el); } @HostListener('ionChange', ['$event.target.checked']) _handleIonChange(value: any) { - if (value !== this.lastValue) { - this.lastValue = value; - this.onChange(value); - } - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); - } - - @HostListener('ionBlur') - _handleBlurEvent() { - this.onTouched(); - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); - } - - registerOnChange(fn: (value: any) => void) { - this.onChange = fn; - } - - registerOnTouched(fn: () => void) { - this.onTouched = fn; - } - - setDisabledState(isDisabled: boolean) { - this.element.nativeElement.disabled = isDisabled; + this.handleChangeEvent(value); } } diff --git a/angular/src/directives/control-value-accessors/numeric-value-accesssor.ts b/angular/src/directives/control-value-accessors/numeric-value-accesssor.ts index c389e5267b..19ea1241a3 100644 --- a/angular/src/directives/control-value-accessors/numeric-value-accesssor.ts +++ b/angular/src/directives/control-value-accessors/numeric-value-accesssor.ts @@ -1,7 +1,6 @@ import { Directive, ElementRef, HostListener } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; - -import { setIonicClasses } from './util/set-ionic-classes'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ValueAccessor } from './value-accessor'; @Directive({ /* tslint:disable-next-line:directive-selector */ @@ -14,56 +13,20 @@ import { setIonicClasses } from './util/set-ionic-classes'; } ] }) -export class NumericValueAccessor implements ControlValueAccessor { +export class NumericValueAccessor extends ValueAccessor { - constructor(private element: ElementRef) { - this.onChange = () => {/**/}; - this.onTouched = () => {/**/}; - } - - onChange: (value: any) => void; - onTouched: () => void; - private lastValue: any; - - writeValue(value: any) { - // The value needs to be normalized for IE9, otherwise it is set to 'null' when null - // Probably not an issue for us, but it doesn't really cost anything either - this.element.nativeElement.value = this.lastValue = value == null ? '' : value; - setIonicClasses(this.element); + constructor(el: ElementRef) { + super(el); } @HostListener('ionChange', ['$event.target.value']) - _handleInputEvent(value: any) { - if (value !== this.lastValue) { - this.lastValue = value; - this.onChange(value); - } - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); - } - - @HostListener('ionBlur') - _handleBlurEvent() { - this.onTouched(); - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); + _handleIonChange(value: any) { + this.handleChangeEvent(value); } registerOnChange(fn: (_: number | null) => void) { - this.onChange = value => { + super.registerOnChange(value => { fn(value === '' ? null : parseFloat(value)); - }; - } - - registerOnTouched(fn: () => void) { - this.onTouched = fn; - } - - setDisabledState(isDisabled: boolean) { - this.element.nativeElement.disabled = isDisabled; + }); } } diff --git a/angular/src/directives/control-value-accessors/radio-value-accessor.ts b/angular/src/directives/control-value-accessors/radio-value-accessor.ts index fd2821cc8f..324c78db66 100644 --- a/angular/src/directives/control-value-accessors/radio-value-accessor.ts +++ b/angular/src/directives/control-value-accessors/radio-value-accessor.ts @@ -1,7 +1,7 @@ -import { Directive, ElementRef, HostListener, Input } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { Directive, ElementRef, HostListener } from '@angular/core'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; -import { setIonicClasses } from './util/set-ionic-classes'; +import { ValueAccessor } from './value-accessor'; @Directive({ /* tslint:disable-next-line:directive-selector */ @@ -14,58 +14,14 @@ import { setIonicClasses } from './util/set-ionic-classes'; } ] }) -export class RadioValueAccessor implements ControlValueAccessor { - @Input() value: any; +export class RadioValueAccessor extends ValueAccessor { - onChange: (value: any) => void; - onTouched: () => void; - private lastValue: any; - - constructor(private element: ElementRef) { - this.onChange = () => {/**/}; - this.onTouched = () => {/**/}; - } - - writeValue(value: any) { - this.element.nativeElement.checked = this.lastValue = this.value = value; - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); + constructor(el: ElementRef) { + super(el); } @HostListener('ionSelect', ['$event.target.checked']) _handleIonSelect(value: any) { - if (value !== this.lastValue) { - this.lastValue = value; - this.onChange(value); - } - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); - } - - @HostListener('ionBlur') - _handleBlurEvent() { - this.onTouched(); - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); - } - - registerOnChange(fn: (value: any) => void) { - this.onChange = () => { - fn(this.value); - }; - } - - registerOnTouched(fn: () => void) { - this.onTouched = fn; - } - - setDisabledState(isDisabled: boolean) { - this.element.nativeElement.disabled = isDisabled; + this.handleChangeEvent(value); } } diff --git a/angular/src/directives/control-value-accessors/select-value-accessor.ts b/angular/src/directives/control-value-accessors/select-value-accessor.ts index ff26a95203..01ded19a73 100644 --- a/angular/src/directives/control-value-accessors/select-value-accessor.ts +++ b/angular/src/directives/control-value-accessors/select-value-accessor.ts @@ -1,7 +1,6 @@ import { Directive, ElementRef, HostListener } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; - -import { setIonicClasses } from './util/set-ionic-classes'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ValueAccessor } from './value-accessor'; @Directive({ /* tslint:disable-next-line:directive-selector */ @@ -14,55 +13,14 @@ import { setIonicClasses } from './util/set-ionic-classes'; } ] }) -export class SelectValueAccessor implements ControlValueAccessor { +export class SelectValueAccessor extends ValueAccessor { - constructor(private element: ElementRef) { - this.onChange = () => {/**/}; - this.onTouched = () => {/**/}; - } - - onChange: (value: any) => void; - onTouched: () => void; - private lastValue: any; - - writeValue(value: any) { - this.element.nativeElement.value = this.lastValue = value; - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); + constructor(el: ElementRef) { + super(el); } @HostListener('ionChange', ['$event.target.value']) _handleChangeEvent(value: any) { - if (value !== this.lastValue) { - this.lastValue = value; - this.onChange(value); - } - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); - } - - @HostListener('ionBlur') - _handleBlurEvent() { - this.onTouched(); - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); - } - - registerOnChange(fn: (value: any) => void) { - this.onChange = fn; - } - - registerOnTouched(fn: () => void) { - this.onTouched = fn; - } - - setDisabledState(isDisabled: boolean) { - this.element.nativeElement.disabled = isDisabled; + this.handleChangeEvent(value); } } diff --git a/angular/src/directives/control-value-accessors/text-value-accessor.ts b/angular/src/directives/control-value-accessors/text-value-accessor.ts index c7446a7b19..eca87a82e8 100644 --- a/angular/src/directives/control-value-accessors/text-value-accessor.ts +++ b/angular/src/directives/control-value-accessors/text-value-accessor.ts @@ -1,7 +1,6 @@ import { Directive, ElementRef, HostListener } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; - -import { setIonicClasses } from './util/set-ionic-classes'; +import { NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ValueAccessor } from './value-accessor'; @Directive({ /* tslint:disable-next-line:directive-selector */ @@ -14,55 +13,14 @@ import { setIonicClasses } from './util/set-ionic-classes'; } ] }) -export class TextValueAccessor implements ControlValueAccessor { +export class TextValueAccessor extends ValueAccessor { - constructor(private element: ElementRef) { - this.onChange = () => {/**/}; - this.onTouched = () => {/**/}; - } - - onChange: (value: any) => void; - onTouched: () => void; - private lastValue: any; - - writeValue(value: any) { - this.element.nativeElement.value = this.lastValue = value; - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); + constructor(el: ElementRef) { + super(el); } @HostListener('ionChange', ['$event.target.value']) _handleInputEvent(value: any) { - if (value !== this.lastValue) { - this.lastValue = value; - this.onChange(value); - } - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); - } - - @HostListener('ionBlur') - _handleBlurEvent() { - this.onTouched(); - - requestAnimationFrame(() => { - setIonicClasses(this.element); - }); - } - - registerOnChange(fn: (value: any) => void) { - this.onChange = fn; - } - - registerOnTouched(fn: () => void) { - this.onTouched = fn; - } - - setDisabledState(isDisabled: boolean) { - this.element.nativeElement.disabled = isDisabled; + this.handleChangeEvent(value); } } diff --git a/angular/src/directives/control-value-accessors/util/set-ionic-classes.ts b/angular/src/directives/control-value-accessors/util/set-ionic-classes.ts deleted file mode 100644 index 23511099cd..0000000000 --- a/angular/src/directives/control-value-accessors/util/set-ionic-classes.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ElementRef } from '@angular/core'; - -export function setIonicClasses(element: ElementRef) { - const classList = element.nativeElement.classList; - - classList.remove('ion-invalid'); - classList.remove('ion-valid'); - classList.remove('ion-touched'); - classList.remove('ion-untouched'); - classList.remove('ion-dirty'); - classList.remove('ion-pristine'); - classList.forEach((cls: string) => { - if (cls === 'ng-invalid') { classList.add('ion-invalid'); } - if (cls === 'ng-valid') { classList.add('ion-valid'); } - if (cls === 'ng-touched') { classList.add('ion-touched'); } - if (cls === 'ng-untouched') { classList.add('ion-untouched'); } - if (cls === 'ng-dirty') { classList.add('ion-dirty'); } - if (cls === 'ng-pristine') { classList.add('ion-pristine'); } - }); -} diff --git a/angular/src/directives/control-value-accessors/value-accessor.ts b/angular/src/directives/control-value-accessors/value-accessor.ts new file mode 100644 index 0000000000..74d5123a2d --- /dev/null +++ b/angular/src/directives/control-value-accessors/value-accessor.ts @@ -0,0 +1,62 @@ +import { ElementRef, HostListener } from '@angular/core'; +import { ControlValueAccessor } from '@angular/forms'; + +export class ValueAccessor implements ControlValueAccessor { + + private onChange: (value: any) => void = () => {/**/}; + private onTouched: () => void = () => {/**/}; + private lastValue: any; + + constructor(private el: ElementRef) {} + + writeValue(value: any) { + this.el.nativeElement.value = this.lastValue = value == null ? '' : value; + setIonicClasses(this.el); + } + + handleChangeEvent(value: any) { + if (value !== this.lastValue) { + this.lastValue = value; + this.onChange(value); + } + setIonicClasses(this.el); + } + + @HostListener('ionBlur') + _handleBlurEvent() { + this.onTouched(); + setIonicClasses(this.el); + } + + registerOnChange(fn: (value: any) => void) { + this.onChange = fn; + } + + registerOnTouched(fn: () => void) { + this.onTouched = fn; + } + + setDisabledState(isDisabled: boolean) { + this.el.nativeElement.disabled = isDisabled; + } +} + +function setIonicClasses(element: ElementRef) { + requestAnimationFrame(() => { + const classList = (element.nativeElement as HTMLElement).classList; + + classList.remove( + 'ion-valid', + 'ion-touched', + 'ion-untouched', + 'ion-dirty', + 'ion-pristine' + ); + + classList.forEach((cls: string) => { + if (cls.startsWith('ng-')) { + classList.add(`ion-${cls.substr(3)}`); + } + }); + }); +}