Javascript 将数字变量绑定到角度域中的屏蔽输入
现在,我的API上的JSON解析要求我的属性必须严格类型化(即int需要从javascript以数字形式发送,而不是试图解析字符串),我们的输入框上的掩码遇到了问题 特别是,我们的货币掩码将绑定变量更改为字符串,而不是将它们保留为数字 是否可以将数字绑定到输入框,让该输入框显示非数字字符,如$,并严格将数字作为数字键入?我尝试在getter上强制使用parseFloat(),但这并没有影响绑定变量的类型 HTML:Javascript 将数字变量绑定到角度域中的屏蔽输入,javascript,angular,Javascript,Angular,现在,我的API上的JSON解析要求我的属性必须严格类型化(即int需要从javascript以数字形式发送,而不是试图解析字符串),我们的输入框上的掩码遇到了问题 特别是,我们的货币掩码将绑定变量更改为字符串,而不是将它们保留为数字 是否可以将数字绑定到输入框,让该输入框显示非数字字符,如$,并严格将数字作为数字键入?我尝试在getter上强制使用parseFloat(),但这并没有影响绑定变量的类型 HTML: 遮罩: import{Directive,ElementRef,HostLi
遮罩:
import{Directive,ElementRef,HostListener,AfterViewInit,Input,forwardRef,Renderer2}来自“@angular/core”;
从“@angular/forms”导入{NG_VALUE_访问器,ControlValueAccessor};
常量noop=()=>{};
导出常量自定义\输入\控制\值\访问器:任意={
提供:NG_值访问器,
useExisting:forwardRef(()=>CurrencyMaskDirective),
多:真的
};
@指示({
选择器:“[appCurrencyMask]”,
提供者:[自定义\输入\控制\值\访问器]
})
导出类CurrencyMaskDirective在ViewInit、ControlValueAccessor之后实现{
私有el:HTMLInputElement;
//跟踪值而不设置格式
私人内在价值:任何;
私有前缀:字符串;
私有小数分隔符:字符串;
私人千人助手:字符串;
//允许负数交互的可选参数
@输入('allowNegative')
allowNegative:布尔型;
构造函数(private-elementRef:elementRef,private-renderer:render2){
this.el=elementRef.nativeElement;
this.prefix='$';
this.decimalSeparator=';
this.thousandsSeparator=',';
}
//稍后提供的回调的占位符d
//通过控制值访问器
私有onTouchedCallback:()=>void=noop;
私有onChangeCallback:(a:any)=>void=noop;
//集吸气剂
获取值():任意{
返回parseFloat(this.innerValue.toString());
}
//设置访问器,包括调用onchange回调
设定值(v:任意){
如果(v!==此.innerValue){
this.innerValue=v;
这是一个错误(v);
}
}
//从ControlValueAccessor接口
writeValue(值:任意){
if(值!==此.innerValue){
this.el.value=this.transform(value,this.allowNegative);
如果(值){
this.renderer.setAttribute(this.elementRef.nativeElement,'value',value);
}
this.innerValue=parseFloat(值?.toString());
}
}
//从ControlValueAccessor接口
注册变更(fn:任何){
this.onChangeCallback=fn;
}
//从ControlValueAccessor接口
注册人(fn:任何){
this.onTouchedCallback=fn;
}
ngAfterViewInit(){
this.el.style.textAlign='right';
}
//在焦点上删除所有非数字或十进制分隔符值
@HostListener('focus',['$event.target.value']))
onfocus(值){
this.el.value=this.parse(value,this.allowNegative);
如果(该值==“0”){
this.el.value=“”;
}
}
//在蓝色上删除除最后一个符号外的所有符号,并设置为货币格式
@HostListener('blur',['$event.target.value']))
onBlur(值){
这个.ontouchdcallback();
this.el.value=this.transform(value,this.allowNegative);
this.innerValue=this.parse(this.el.value,this.allowNegative);
this.onChangeCallback(this.innerValue);
if(this.innerValue){
this.renderer.setAttribute(this.elementRef.nativeElement,'value',this.innerValue);
}
}
//更改时删除除last.之外的所有符号,并设置为货币格式
@HostListener('change',['$event.target.value']))
onChange(值){
this.el.value=this.transform(value,this.allowNegative);
this.innerValue=this.parse(this.el.value,this.allowNegative);
this.onChangeCallback(this.innerValue);
if(this.innerValue){
this.renderer.setAttribute(this.elementRef.nativeElement,'value',this.innerValue);
}
}
//禁止用户输入除数字和小数分隔符以外的任何内容
@HostListener('keypress',['$event']))
onKeyPress(事件){
const key=event.which | | event.keyCode | 0;
if(key==45&&!this.allowNegative){
event.preventDefault();
}else if(key==45&&this.allowNegative){
//允许负数
}否则,如果(键!==46&&key>31&&key<48 | | key>57)){
event.preventDefault();
}
}
转换(值:string,allowNegative=false,decimalPrecision:number=2){
如果(值==未定义| |值==''){
返回“$0.00”;
}
if(allowNegative){
value=value.toString();
if(value.startsWith(“(”)| | value.startsWith(“-”){
value='-'+value.substr(1,value.length).replace(/\(\\)\$\\-/g');
}否则{
值=值。替换(/\(\\)\$\-/g',);
}
}
让[integer,fraction='']=(value | |'''..toString().split(this.decimalSeparator);
分数=小数精度>0?此.decimalSeparator+(分数+'000000')。子字符串(0,2):“”;
如果(integer.indexOf(',')<0){//1000个参数尚未添加
如果(!isNaN(parseInt(整数))){
integer=parseInt(integer).toString();//删除前导0
}
}
integer=integer.replace(/\B(?=(\d{3})+(?!\d))/g,这个.thousandsSeparator);
//如果用户输入.xx,我们可以显示0.xx
如果(整数==''){
我
<input appCurrencyMask [(ngModel)]="_variable" />
import { Directive, ElementRef, HostListener, AfterViewInit, Input, forwardRef, Renderer2 } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
const noop = () => { };
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CurrencyMaskDirective),
multi: true
};
@Directive({
selector: '[appCurrencyMask]',
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
})
export class CurrencyMaskDirective implements AfterViewInit, ControlValueAccessor {
private el: HTMLInputElement;
// Keeps track of the value without formatting
private innerValue: any;
private prefix: string;
private decimalSeparator: string;
private thousandsSeparator: string;
// Optional Parameter to allow for negative number interaction
@Input('allowNegative')
allowNegative: boolean;
constructor(private elementRef: ElementRef, private renderer: Renderer2) {
this.el = elementRef.nativeElement;
this.prefix = '$';
this.decimalSeparator = '.';
this.thousandsSeparator = ',';
}
// Placeholders for the callbacks which are later providesd
// by the Control Value Accessor
private onTouchedCallback: () => void = noop;
private onChangeCallback: (a: any) => void = noop;
// set getter
get value(): any {
return parseFloat(this.innerValue.toString());
}
// set accessor including call the onchange callback
set value(v: any) {
if (v !== this.innerValue) {
this.innerValue = v;
this.onChangeCallback(v);
}
}
// From ControlValueAccessor interface
writeValue(value: any) {
if (value !== this.innerValue) {
this.el.value = this.transform(value, this.allowNegative);
if (value) {
this.renderer.setAttribute(this.elementRef.nativeElement, 'value', value);
}
this.innerValue = parseFloat(value?.toString());
}
}
// From ControlValueAccessor interface
registerOnChange(fn: any) {
this.onChangeCallback = fn;
}
// From ControlValueAccessor interface
registerOnTouched(fn: any) {
this.onTouchedCallback = fn;
}
ngAfterViewInit() {
this.el.style.textAlign = 'right';
}
// On Focus remove all non-digit or decimal separator values
@HostListener('focus', ['$event.target.value'])
onfocus(value) {
this.el.value = this.parse(value, this.allowNegative);
if (this.el.value == "0") {
this.el.value = "";
}
}
// On Blue remove all symbols except last . and set to currency format
@HostListener('blur', ['$event.target.value'])
onBlur(value) {
this.onTouchedCallback();
this.el.value = this.transform(value, this.allowNegative);
this.innerValue = this.parse(this.el.value, this.allowNegative);
this.onChangeCallback(this.innerValue);
if (this.innerValue) {
this.renderer.setAttribute(this.elementRef.nativeElement, 'value', this.innerValue);
}
}
// On Change remove all symbols except last . and set to currency format
@HostListener('change', ['$event.target.value'])
onChange(value) {
this.el.value = this.transform(value, this.allowNegative);
this.innerValue = this.parse(this.el.value, this.allowNegative);
this.onChangeCallback(this.innerValue);
if (this.innerValue) {
this.renderer.setAttribute(this.elementRef.nativeElement, 'value', this.innerValue);
}
}
// Prevent user to enter anything but digits and decimal separator
@HostListener('keypress', ['$event'])
onKeyPress(event) {
const key = event.which || event.keyCode || 0;
if (key === 45 && !this.allowNegative) {
event.preventDefault();
} else if (key === 45 && this.allowNegative) {
// allow negative numbers
} else if (key !== 46 && key > 31 && (key < 48 || key > 57)) {
event.preventDefault();
}
}
transform(value: string, allowNegative = false, decimalPrecision: number = 2) {
if (value == undefined || value === '') {
return "$0.00";
}
if (allowNegative) {
value = value.toString();
if (value.startsWith('(') || value.startsWith('-')) {
value = '-' + value.substr(1, value.length).replace(/\(|\)|\$|\-/g, '');
} else {
value = value.replace(/\(|\)|\$|\-/g, '');
}
}
let [integer, fraction = ''] = (value || '').toString().split(this.decimalSeparator);
fraction = decimalPrecision > 0 ? this.decimalSeparator + (fraction + '000000').substring(0, 2) : '';
if (integer.indexOf(',') < 0) { //thousandsSeparators have not been added yet
if (!isNaN(parseInt(integer))) {
integer = parseInt(integer).toString(); //remove leading 0s
}
}
integer = integer.replace(/\B(?=(\d{3})+(?!\d))/g, this.thousandsSeparator);
// If user types .xx we can display 0.xx
if (integer === '') {
integer = '0';
} else if (integer.startsWith('$')) {
// If there are multiple transforms, remove the previous dollar sign (blur and change at the same time)
integer = integer.substr(1, integer.length);
} else if (allowNegative && integer.startsWith('-')) {
// If user inputs negative number set to paranthesis format
integer = integer.substr(1, integer.length);
return '(' + this.prefix + integer + fraction + ')';
}
return this.prefix + integer + fraction;
}
parse(value: string, allowNegative = false) {
let [integer, fraction = ''] = (value || '').split(this.decimalSeparator);
integer = integer.replace(new RegExp(/[^\d\.]/, 'g'), '');
fraction = parseInt(fraction, 10) > 0 && 2 > 0 ? this.decimalSeparator + (fraction + '000000').substring(0, 2) : '';
if (allowNegative && value.startsWith('(') && value.endsWith(')')) {
return (-1 * parseFloat(integer + fraction)).toString();
} else {
return integer + fraction;
}
}
}
parse(value)