feat(numeric-input): create number input control value accessor

This commit is contained in:
Ken Sodemann
2017-12-11 11:01:34 -06:00
parent 4d36369a74
commit 903a12dc39
5 changed files with 105 additions and 4 deletions

View File

@ -0,0 +1,62 @@
import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Directive({
/* tslint:disable-next-line:directive-selector */
selector: 'ion-input[type=number]',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: NumericValueAccessor,
multi: true
}
]
})
export class NumericValueAccessor implements ControlValueAccessor {
constructor(private element: ElementRef, private renderer: Renderer2) {
this.onChange = () => {};
this.onTouched = () => {};
}
onChange: (value: any) => void;
onTouched: () => void;
writeValue(value: any): void {
// 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
const normalizedValue = value == null ? '' : value;
this.renderer.setProperty(
this.element.nativeElement,
'value',
normalizedValue
);
}
@HostListener('input', ['$event.target.value'])
_handleInputEvent(value: any): void {
this.onChange(value);
}
@HostListener('ionBlur')
_handleBlurEvent(): void {
this.onTouched();
}
registerOnChange(fn: (_: number | null) => void): void {
this.onChange = value => {
fn(value == '' ? null : parseFloat(value));
};
}
registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}
setDisabledState(isDisabled: boolean): void {
this.renderer.setProperty(
this.element.nativeElement,
'disabled',
isDisabled
);
}
}

View File

@ -1,11 +1,9 @@
import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core'; import { Directive, ElementRef, HostListener, Renderer2 } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
// NOTE: May need to look at this to see if we need anything else:
// https://github.com/angular/angular/blob/5.0.1/packages/forms/src/directives/default_value_accessor.ts#L33-L101
@Directive({ @Directive({
/* tslint:disable-next-line:directive-selector */ /* tslint:disable-next-line:directive-selector */
selector: 'ion-input,ion-textarea', selector: 'ion-input:not([type=number]),ion-textarea',
providers: [ providers: [
{ {
provide: NG_VALUE_ACCESSOR, provide: NG_VALUE_ACCESSOR,
@ -44,4 +42,12 @@ export class TextValueAccessor implements ControlValueAccessor {
registerOnTouched(fn: () => void) { registerOnTouched(fn: () => void) {
this.onTouched = fn; this.onTouched = fn;
} }
setDisabledState(isDisabled: boolean): void {
this.renderer.setProperty(
this.element.nativeElement,
'disabled',
isDisabled
);
}
} }

View File

@ -5,6 +5,7 @@ import {
} from '@angular/core'; } from '@angular/core';
import { BooleanValueAccessor } from './control-value-accessors/boolean-value-accessor'; import { BooleanValueAccessor } from './control-value-accessors/boolean-value-accessor';
import { NumericValueAccessor } from './control-value-accessors/numeric-value-accesssor';
import { RadioValueAccessor } from './control-value-accessors/radio-value-accessor'; import { RadioValueAccessor } from './control-value-accessors/radio-value-accessor';
import { SelectValueAccessor } from './control-value-accessors/select-value-accessor'; import { SelectValueAccessor } from './control-value-accessors/select-value-accessor';
import { TextValueAccessor } from './control-value-accessors/text-value-accessor'; import { TextValueAccessor } from './control-value-accessors/text-value-accessor';
@ -23,6 +24,7 @@ import { ToastController } from './providers/toast-controller';
declarations: [ declarations: [
BooleanValueAccessor, BooleanValueAccessor,
IonNavDelegate, IonNavDelegate,
NumericValueAccessor,
RadioValueAccessor, RadioValueAccessor,
SelectValueAccessor, SelectValueAccessor,
TextValueAccessor TextValueAccessor
@ -30,6 +32,7 @@ import { ToastController } from './providers/toast-controller';
exports: [ exports: [
BooleanValueAccessor, BooleanValueAccessor,
IonNavDelegate, IonNavDelegate,
NumericValueAccessor,
RadioValueAccessor, RadioValueAccessor,
SelectValueAccessor, SelectValueAccessor,
TextValueAccessor TextValueAccessor

View File

@ -30,6 +30,30 @@
</ion-col> </ion-col>
</ion-row> </ion-row>
<ion-row>
<ion-col>
<h2>Numeric Input</h2>
</ion-col>
</ion-row>
<ion-row>
<ion-col>
<ion-item>
<ion-label>Ionic Numeric Input</ion-label>
<ion-input type="number" id="ionNumberInput" name="ionNumberInput" [(ngModel)]="numberValue"></ion-input>
</ion-item>
</ion-col>
<ion-col>
<div>
Value:
<span id="numberOutput">{{numberValue}}</span>
</div>
<div>
Type:
<span id="numberOutputType">{{typeOf(numberValue)}}</span>
</div>
</ion-col>
</ion-row>
<ion-row> <ion-row>
<ion-col> <ion-col>
<h2>Textarea Input</h2> <h2>Textarea Input</h2>
@ -127,7 +151,8 @@
<ion-col> <ion-col>
<ion-item> <ion-item>
<ion-label>Ionic Date</ion-label> <ion-label>Ionic Date</ion-label>
<ion-datetime id="ionDatetimeInput" pickerFormat="YYYY-MM-DD HH:mm:ss" displayFormat="MM/DD/YYYY HH:mm:ss" name="ionDatetimeInput" [(ngModel)]="datetimeValue"></ion-datetime> <ion-datetime id="ionDatetimeInput" pickerFormat="YYYY-MM-DD HH:mm:ss" displayFormat="MM/DD/YYYY HH:mm:ss" name="ionDatetimeInput"
[(ngModel)]="datetimeValue"></ion-datetime>
</ion-item> </ion-item>
</ion-col> </ion-col>
<ion-col> <ion-col>

View File

@ -10,6 +10,7 @@ export class BasicInputsPageComponent implements OnInit {
datetimeValue = '2017-11-18T14:17:45-06:00'; datetimeValue = '2017-11-18T14:17:45-06:00';
textareaValue = 'This is the Textarea Input'; textareaValue = 'This is the Textarea Input';
textValue = 'This is the Text Input'; textValue = 'This is the Text Input';
numberValue = 1138;
checkboxValue = true; checkboxValue = true;
toggleValue = false; toggleValue = false;
@ -17,4 +18,8 @@ export class BasicInputsPageComponent implements OnInit {
constructor() {} constructor() {}
ngOnInit() {} ngOnInit() {}
typeOf(v: any): string {
return typeof v;
}
} }