import { ChangeDetectionStrategy , ChangeDetectorRef , Component , EventEmitter , forwardRef , Input , Output , ViewEncapsulation } from '@angular/core' ; import { ControlValueAccessor , NG_VALUE_ACCESSOR } from '@angular/forms' ; export const SPIN_BUTTON_VALUE_ACCESSOR = { provide : NG_VALUE_ACCESSOR , useExisting : forwardRef ( ( ) => SpinButtonComponent ) , multi : true } ; @ Component ( { selector : 'ux-spin-button' , templateUrl : './spin-button.component.html' , encapsulation : ViewEncapsulation . None , changeDetection : ChangeDetectionStrategy . OnPush , providers : [ SPIN_BUTTON_VALUE_ACCESSOR ] } ) export class SpinButtonComponent implements ControlValueAccessor { @ Input ( ) set value ( value ) { this . _value = value ; this . onChangeCallback ( value ) ; this . onTouchedCallback ( ) ; } get value ( ) : string | number { return this . _value ; } @ Input ( ) type : string = 'text' ; @ Input ( ) min : number ; @ Input ( ) max : number ; @ Input ( ) placeholder : string = '' ; @ Input ( ) disabled : boolean = false ; @ Input ( ) spinners : boolean = true ; @ Input ( ) readOnly : boolean = true ; @ Input ( ) scrolling : boolean = true ; @ Input ( ) arrowkeys : boolean = true ; @ Input ( ) maxLength : number = Infinity ; @ Input ( ) incrementAriaLabel : string ; @ Input ( ) inputAriaLabel : string ; @ Input ( ) decrementAriaLabel : string ; @ Output ( ) valueChange = new EventEmitter < string | number > ( ) ; @ Output ( ) increment = new EventEmitter < void > ( ) ; @ Output ( ) decrement = new EventEmitter < void > ( ) ; onTouchedCallback : ( ) => void = ( ) => { } ; onChangeCallback : ( _ : string | number ) => void = ( ) => { } ; private _value : string | number ; private _regexKeypress = RegExp ( /^[0-9.,-]+$/ ) ; private _regexPaste = RegExp ( /^\-?\d+(\.\d+)?$/ ) ; constructor ( private readonly _changeDetector ) { } scroll ( event ) { if ( ! this . scrolling ) { return ; } if ( event . deltaY > 0 ) { this . triggerDecrement ( ) ; } else { this . triggerIncrement ( ) ; } event . preventDefault ( ) ; } triggerIncrement ( ) { if ( ! this . disabled ) { this . increment . emit ( ) ; } } triggerDecrement ( ) { if ( ! this . disabled ) { this . decrement . emit ( ) ; } } writeValue ( value ) { this . value = value ; this . _changeDetector . markForCheck ( ) ; } registerOnChange ( fn ) { this . onChangeCallback = fn ; } registerOnTouched ( fn ) { this . onTouchedCallback = fn ; } setDisabledState ( isDisabled ) { this . disabled = isDisabled ; this . _changeDetector . markForCheck ( ) ; } onKeypress ( event ) { if ( this . type !== 'number' ) { return ; } if ( ! this . _regexKeypress . test ( event . key ) ) { return false ; } return true ; } onPaste ( event ) { if ( this . type !== 'number' ) { return ; } const value = event . clipboardData . getData ( 'text' ) ; if ( ! this . _regexPaste . test ( value ) ) { const numericValue = parseFloat ( value ) ; if ( ! isNaN ( numericValue ) ) { this . value = numericValue ; } event . stopPropagation ( ) ; event . preventDefault ( ) ; } } onValueChange ( input , value ) { if ( typeof value === 'string' && value . length > this . maxLength ) { if ( this . type === 'number' ) { value = parseFloat ( value ) . toString ( ) ; } value = value . substring ( 0 , this . maxLength ) ; input . value = value ; } this . valueChange . emit ( value ) ; } }