2017-04-21 48 views
1

更新最初雖然問題在於ControlValueAccessor的實現,隨後確定的問題是將ControlValueAccessor應用於子元素。編輯反映的問題。如何實現離子輸入的貨幣輸入指令

我想提供一個屬性指令,它將以'美元'格式(例如10.00)顯示貨幣值,但會以美分(例如1000)的形式存儲在底層模型中。

<!-- cost = 1000 would result in text input value of 10.00 
<input type="text" [(ngModel)]="cost" name="cost" currencyInput> 
<!-- or in Ionic 2 --> 
<ion-input type="text" [(ngModel)]="cost" name="cost-ionic" currencyInput> 

以前在AngularJS 1.x中我會使用解析和渲染在指令鏈路功能如下:

(function() { 
    'use strict'; 

    angular.module('app.directives').directive('ndDollarsToCents', ['$parse', function($parse) { 
     return { 
      require: 'ngModel', 
      link: function(scope, element, attrs, ctrl) { 
       var listener = function() { 
        element.val((value/100).toFixed(2)); 
       }; 

       ctrl.$parsers.push(function(viewValue) { 
        return Math.round(parseFloat(viewValue) * 100); 
       }); 

       ctrl.$render = function() { 
        element.val((ctrl.$viewValue/100).toFixed(2)); 
       }; 

       element.bind('change', listener); 
      } 
     }; 
    }]); 
})(); 

在離子2 /角2 I實現此使用ControlValueAccessor接口具有如下:

import { Directive, Renderer, ElementRef, forwardRef } from '@angular/core'; 
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; 

const CURRENCY_VALUE_ACCESSOR = { 
    provide: NG_VALUE_ACCESSOR, 
    useExisting: forwardRef(() => CurrencyInputDirective), 
    multi: true 
} 

@Directive({ 
    selector: '[currencyInput]', 
    host: { 
     '(input)': 'handleInput($event.target.value)' 
    }, 
    providers: [ CURRENCY_VALUE_ACCESSOR ] 
}) 
export class CurrencyInputDirective implements ControlValueAccessor, AfterViewInit 
{ 
    onChange = (_: any) => {}; 
    onTouched =() => {}; 
    inputElement: HTMLInputElement = null; 

    constructor(private renderer: Renderer, private elementRef: ElementRef) {} 

    ngAfterViewInit() 
    { 
     let element = this.elementRef.nativeElement; 

     if(element.tagName === 'INPUT') 
     { 
      this.inputElement = element; 
     } 
     else 
     { 
      this.inputElement = element.getElementsByTagName('input')[0]; 
     } 
    } 

    registerOnChange(fn: (_: any) => void): void { this.onChange = fn; } 
    registerOnTouched(fn:() => void): void { this.onTouched = fn; } 

    handleInput(value : string) 
    { 
     if (value) 
     { 
      value = String(Math.round(parseFloat(value) * 100)); 
     } 

     this.onChange(value); 
    } 


    writeValue(value: any): void 
    { 
     if (value) 
     { 
      value = (parseInt(value)/100).toFixed(2); 
     } 

     this.renderer.setElementProperty(this.inputElement, 'value', value); 
    } 
} 

雖然這適用於直接輸入元素時適用於離子輸入它不起作用罰款。有沒有辦法讓ControlValueAccessor應用於離子輸入的子輸入元素?

+0

輸入和輸出??示例 – Aravind

+0

在下面看到我的答案 – Aravind

回答

2

雖然ControlAccessorValue方法是適合普通<input>元素我無法得到的指令來充當<ion-input>指令的<input>子元件的控制訪問(對此有興趣的解決方案)。

import { Directive, Renderer, ElementRef, Input, Output, EventEmitter, AfterViewInit } from '@angular/core'; 

@Directive({ 
    selector: '[currencyInput]', 
    host: { 
     '(input)': 'handleInput($event.target.value)' 
    }, 
}) 
export class CurrencyInputDirective implements AfterViewInit 
{ 

    @Input('currencyInput') currency: number; 
    @Output('currencyInputChange') currencyChange: EventEmitter<number> = new EventEmitter<number>(); 
    inputElement: HTMLInputElement = null; 

    constructor(private renderer: Renderer, private el: ElementRef) { } 

    ngAfterViewInit() 
    { 
     let element = this.el.nativeElement; 

     if(element.tagName === 'INPUT') 
     { 
      this.inputElement = element; 
     } 
     else 
     { 
      this.inputElement = element.getElementsByTagName('input')[0]; 
     } 

     setTimeout(() => { 
      this.renderer.setElementProperty(this.inputElement, 'value', (this.currency/100).toFixed(2)); 
     }, 150); 
    } 

    handleInput(value: string) 
    { 
     let v : number = Math.round(parseFloat(value) * 100) 
     this.currencyChange.next(v); 
    } 
} 

,然後應用它的元件上,如下所示::

<ion-input type="text" name="measured_cost" [(currencyInput)]="item.cost"> 

是必需的setTimeout

替代地,下面的指令,當施加至<ion-input>或純<input>達到所期望的結果以確保輸入字段由CurrencyInputDirective而不是離子(我歡迎一個更好的選擇)初始化。

這可以正常工作,但它只提供單向流動,即如果item.cost在輸入元素之外更改,它不會反映在輸入元素值中。這個問題可以利用currencyInput setter方法如顯示在下面的這個較少高性能溶液加以處理:

import { Directive, Renderer, ElementRef, Input, Output, EventEmitter, AfterViewInit } from '@angular/core'; 
@Directive({ 
    selector: '[currencyInput]', 
    host: { 
     '(input)': 'handleInput($event.target.value)' 
    }, 
}) 
export class CurrencyInputDirective implements AfterViewInit 
{ 
    _cents: number; 
    myUpdate: boolean = false; 
    inputElement: HTMLInputElement = null; 
    @Input('currencyInput') 
    set cents(value: number) { 
     if(value !== this._cents) 
     { 
      this._cents = value; 
      this.updateElement(); 
     } 
    } 
    @Output('currencyInputChange') currencyChange: EventEmitter<number> = new EventEmitter<number>(); 

    constructor(private renderer: Renderer, private el: ElementRef) { } 

    ngAfterViewInit() 
    { 
     let element = this.el.nativeElement; 

     if(element.tagName === 'INPUT') 
     { 
      this.inputElement = element; 
     } 
     else 
     { 
      this.inputElement = element.getElementsByTagName('input')[0]; 
     } 

     setTimeout(() => { 
      this.renderer.setElementProperty(this.inputElement, 'value', (this._cents/100).toFixed(2)); 
     }, 150); 
    } 

    handleInput(value: string) 
    { 
     let v : number = Math.round(parseFloat(value) * 100); 
     this.myUpdate = true; 
     this.currencyChange.next(v); 
    } 

    updateElement() 
    { 
     if(this.inputElement) 
     { 
      let startPos = this.inputElement.selectionStart; 
      let endPos = this.inputElement.selectionEnd; 

      this.renderer.setElementProperty(this.inputElement, 'value', (this._cents/100).toFixed(2)); 
      if(this.myUpdate) 
      { 
       this.inputElement.setSelectionRange(startPos, endPos); 
       this.myUpdate = false; 
      } 
     } 
    } 
} 
0

您無需使用ControlValueAccessor即可實現此目的。使用下面的代碼

import { Directive, HostListener, Renderer2, ElementRef } from '@angular/core'; 
@Directive({ 
    selector: '[currency]' 
}) 
export class CurrencyDirective{ 

    constructor(
     private renderer: Renderer2, 
     private el: ElementRef 
    ){} 

    @HostListener('keyup') onKeyUp() { 
     this.el.nativeElement.value=this.el.nativeElement.value/100; 
     console.log(this.el.nativeElement.value) 
    console.log('some thing key upped') 

    } 
} 

LIVE DEMO

+0

這並不能完全提供所需的功能,因爲您在該字段中鍵入該字段會更改您的值。我之後在初始化時將文本字段的值設置爲模型/ 100的值,隨後在直接更改文本字段值時將模型值設置爲文本字段值* 100. – cubiclewar

+0

I沒有得到你。當你需要一些東西並且改變時你需要其他東西?或聚焦或模糊 – Aravind

+0

模型值將以美分格式I.e 1000從數據庫中拉出。當文本字段被初始化時,它的值將被設置爲10.00。從那裏,文本字段中的任何按鍵事件都會將模型值設置爲文本字段值乘以100。 – cubiclewar