2017-04-21 2 views
1

업데이트 : 문제는 ControlValueAccessor의 구현에 있었지만 이후 문제는 ControlValueAccessor를 하위 요소에 적용하는 것이 었습니다. 반영하도록 수정 된 질문.이온 입력을위한 통화 입력 지시문을 구현하는 방법

나는 '달러'형식 (예를 들어, 10.00)에서 통화 값을 표시 것이지만 센트로서 기본 모델 (예를 들어, 1000)에 저장 될 속성 지침을 제공하고자합니다. ControlValueAccessor 인터페이스를 사용하여이 다음이

(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 각도 내가 구현 다음과 같이

<!-- 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에서에 내가 지시 링크 기능에서 구문 분석을 사용하여 렌더링 것이다 :

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

를 사용하여 (이것에 대한 해결책에 관심이있다). 다음과 같이

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); 
    } 
} 

하고 요소에 적용 : 다음 setTimeout

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

요구되는 <ion-input> 또는 일반 <input> 적용될 때 대안

다음 지시문은, 원하는 결과를 달성 입력 필드가 이온이 아닌 CurrencyInputDirective으로 초기화되도록합니다 (더 나은 대안을 환영합니다).

이것은 잘 작동하지만 단방향 흐름만을 제공합니다. 즉, item.cost이 입력 요소 외부에서 변경되면 입력 요소 값에 반영되지 않습니다. 이 문제는 다음 성능이 낮은 솔루션에 표시된대로 currencyInput에 대한 설정 메서드를 사용하여 해결할 수 있습니다.

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

이렇게하려면 을 사용할 필요가 없습니다. ControlAccessorValue의 접근 방식은 일반 <input> 요소에 적합 동안 나는 <ion-input> 지침의 <input> 자식 요소에 대한 제어 접근의 역할을 할 수있는 지침을 얻을 수 아래의 코드

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

너를 못 봤어. init을 할 때 뭔가 다른 것이 필요합니다. 초점 또는 블러에 대해서 – Aravind

+0

모델 값은 센트 형식 (즉, 1000)으로 데이터베이스에서 가져옵니다.텍스트 필드가 초기화되면 값은 10.00으로 설정됩니다. 여기에서 텍스트 필드의 모든 키 누르기 이벤트는 모델 값을 텍스트 필드 값에 100을 곱한 값으로 설정합니다. – cubiclewar