Update :最初问题出在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中我会在指令链接函数中使用parse和render,如下所示:
(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);
}
};
}]);
})();
在Ionic 2 / Angular 2中,我使用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应用于离子输入的子输入元素?
2 回答
虽然ControlAccessorValue方法适用于普通的
<input>
元素,但我无法使该指令充当<ion-input>
指令的<input>
子元素的控件访问器(对此解决方案感兴趣) .或者,以下指令在应用于
<ion-input>
或普通<input>
时实现所需的结果:然后将其应用于元素,如下所示:
setTimeout
需要确保输入字段由CurrencyInputDirective
初始化而不是离子(我欢迎更好的选择) .这样可以正常工作,但它只提供单向流,即如果
item.cost
在输入元素之外被更改,则它不会反映在输入元素值中 . 可以使用currencyInput
的setter方法解决此问题,如下面的性能较低的解决方案所示:您无需使用
ControlValueAccessor
来实现此目的 . 使用以下代码LIVE DEMO