Angular 5,输入格式和解析,什么是标准解决方案

Angular 5,输入格式和解析,什么是标准解决方案,angular,angular5,Angular,Angular5,我有一个输入字段,希望使用德语区域设置输入一个浮点数。我的解决方案如下,它是有效的,但它是复杂的,应该有一个更好的方法吗 <input matInput [ngModel]="amount | number: '0.2-2'" (blur)="transformAmount($event)" (keyup.enter)="transformAmount($event)"/> transformAmount(event) { console.log(event.target.v

我有一个输入字段,希望使用德语区域设置输入一个浮点数。我的解决方案如下,它是有效的,但它是复杂的,应该有一个更好的方法吗

<input matInput [ngModel]="amount | number: '0.2-2'" 
(blur)="transformAmount($event)" (keyup.enter)="transformAmount($event)"/>

transformAmount(event) {
  console.log(event.target.value);
  this.amount = parseFloat(event.target.value.replace('.', '').replace(',','.'));
  console.log('amount=' + this.amount);
}

金额(事件){
日志(event.target.value);
this.amount=parseFloat(event.target.value.replace('.','').replace('.','.');
console.log('amount='+this.amount);
}
你的方法很好

将数据从变量转换为
输入
的最佳方法莫过于
管道
,将数据从
输入
转换为变量的最佳方法莫过于绑定到DOM事件的函数

为了简化代码,您可以执行以下操作:

<input matInput [ngModel]="amount | number: '0.2-2'" (ngModelChange)="transformAmount($event)"/>

transformAmount(event) {
  console.log(event);
  this.amount = parseFloat(event.replace('.', '').replace(',','.'));
  console.log('amount=' + this.amount);
}

金额(事件){
console.log(事件);
this.amount=parseFloat(event.replace('.','').replace('.','.');
console.log('amount='+this.amount);
}

是的,这部分有点棘手。此外,有时您需要显示一些并非实际值的内容

我找到的实际最佳解决方案是为我的输入创建一个自定义组件(使用ngModel,请参阅关于ControlValueAccessor),这一个基于您正在尝试的操作

html:

<input [formControl]="inputFormControl" #myInput />

在某种程度上,你肯定会发现它有点复杂,但最终它也会给你更多的控制权;)

我使用本文中的信息创建了一个指令

它正在工作,但我不理解为什么“更改”后缀是必要的,为什么我不能将事件从输入行中分离出来,这样做:(appNumberInput)=。。。。[appNumberInput]=

<input [(appNumberInput)]="amount" format="0.2-2" />

我在格式化被动表单输入字段时遇到了类似的问题。为了解决这个问题,我用了这个。我已经创建了一个稍微修改过的版本来满足我的需要

import { Directive, ElementRef, forwardRef, HostListener, Input, OnDestroy } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MAT_INPUT_VALUE_ACCESSOR } from '@angular/material';
import { Subscription } from 'rxjs';
import { formatNumber } from '@angular/common';

@Directive({
  selector: 'input[localizedNumericInput]',
  providers: [
    { provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: LocalizedNumericInputDirective },
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => LocalizedNumericInputDirective),
      multi: true
    }
  ]
})
export class LocalizedNumericInputDirective implements ControlValueAccessor, OnDestroy {
  locale = 'en';
  decimalMarker: string;

  constructor(private element: ElementRef<HTMLInputElement>) {
  }

  private _value: string | null;

  get value(): string | null {
    return this._value;
  }

  @Input('value')
  set value(value: string | null) {
    this._value = value;
    this.formatValue(value);
  }

  @HostListener('input', ['$event.target.value'])
  input(value) {
    //Find all numerics, decimal marker(, or .) and -
    //It will delete thousandSeparator cos it's always opposite to decimal marker
    const regExp = new RegExp(`[^\\d${this.decimalMarker}-]`, 'g');
    //Separate value on before and after decimal marker
    const [integer, decimal] = value.replace(regExp, '').split(this.decimalMarker);

    //Send non localized value, with dot as decimalMarker to API
    this._value = decimal ? integer.concat('.', decimal) : integer;

    // If decimal separator is last character don't update
    // because it will delete . || ,
    if (this.isLastCharacterDecimalSeparator(value)) {
      this._value = value;
    }

    // here to notify Angular Validators
    this._onChange(this._value);
  }

  @HostListener('blur')
  _onBlur() {
    /**
     * Adding thousand separators
     */
    this.formatValue(this._value);
  }

  @HostListener('focus')
  onFocus() {
    this.unFormatValue();
  }

  _onChange(value: any): void {}

  /**
   * @param value
   * apply formatting on value assignment
   */
  writeValue(value: any) {
    this._value = value;
    this.formatValue(this._value);
  }

  registerOnChange(fn: (value: any) => void) {
    this._onChange = fn;
  }

  registerOnTouched() {}

  isLastCharacterDecimalSeparator(value: any) {
    return isNaN(value[value.length - 1]);
  }


  private formatValue(value: string | null) {
    if (value === null) {
      this.element.nativeElement.value = '';
      return;
    }

    if (this.isLastCharacterDecimalSeparator(value)) {
      this.element.nativeElement.value = value;
      return;
    }

    // Conclude the decimal and thousand separators from locale
    const [thousandSeparator, decimalMarker] = formatNumber(1000.99, this.locale).replace(/\d/g, '');
    this.decimalMarker = decimalMarker;

    //Here value should always come with . as decimal marker thus any other behavior is bug
    const [integer, decimal] = value.split('.');

    //Group every three elements, and add thousandSeparator after them
    this.element.nativeElement.value = integer.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator);

    //Add decimals and decimalMarker if any
    if (decimal) {
      this.element.nativeElement.value = this.element.nativeElement.value.concat(decimalMarker, decimal);
    }
  }

  private unFormatValue() {
    const value = this.element.nativeElement.value;
    if (this.isLastCharacterDecimalSeparator(value)) {
      return;
    }
    const regExp = new RegExp(`[^\\d${this.decimalMarker}-]`, 'g');
    const [integer, decimal] = value.replace(regExp, '').split(this.decimalMarker);

    this._value = integer.concat('.', decimal);
    if (value) {
      this.element.nativeElement.value = this._value;
    } else {
      this.element.nativeElement.value = '';
    }
  }
}
import{Directive,ElementRef,forwardRef,HostListener,Input,OnDestroy}来自“@angular/core”;
从'@angular/forms'导入{ControlValueAccessor,NG_VALUE_ACCESSOR};
从“@angular/material”导入{MAT_INPUT_VALUE_ACCESSOR};
从“rxjs”导入{Subscription};
从“@angular/common”导入{formatNumber};
@指示({
选择器:“输入[localizedNumericInput]”,
供应商:[
{provide:MAT\u INPUT\u VALUE\u ACCESSOR,useExisting:LocalizedNumericInputDirective},
{
提供:NG_值访问器,
useExisting:forwardRef(()=>LocalizedNumericInputDirective),
多:真的
}
]
})
导出类LocalizedNumericInputDirective实现ControlValueAccessor、OnDestroy{
语言环境='en';
小数标记:字符串;
构造函数(私有元素:ElementRef){
}
private _值:字符串| null;
获取值():字符串| null{
返回此值;
}
@输入('值')
设置值(值:字符串| null){
此值为._值=值;
这个值(value);
}
@HostListener('输入',['$event.target.value']))
输入(值){
//查找所有数字、十进制标记(、或)和-
//它将删除千位分隔符,因为它始终与十进制标记相反
const regExp=new regExp(`[^\\d${this.decimalMarker}-]`g');
//将小数点标记前后的值分开
const[integer,decimal]=value.replace(regExp.),.split(this.decimalMarker);
//发送非本地化值,以点作为小数点标记到API
此._值=十进制?整数.concat('.',十进制):整数;
//如果小数点分隔符是最后一个字符,则不更新
//因为它将删除,
if(此.isLastCharacterDecimalSeparator(值)){
此值为._值=值;
}
//在这里通知角度验证器
此._onChange(此._值);
}
@HostListener('blur')
_onBlur(){
/**
*添加千个分隔符
*/
this.formatValue(this.u值);
}
@HostListener('焦点')
onFocus(){
此值为.unFormatValue();
}
_onChange(值:any):void{}
/**
*@param值
*在赋值时应用格式
*/
writeValue(值:任意){
此值为._值=值;
this.formatValue(this.u值);
}
registerOnChange(fn:(值:any)=>void){
这个。_onChange=fn;
}
寄存器(){}
isLastCharacterDecimalSeparator(值:任意){
返回isNaN(值[value.length-1]);
}
私有格式值(值:字符串| null){
如果(值===null){
this.element.nativeElement.value='';
返回;
}
if(此.isLastCharacterDecimalSeparator(值)){
this.element.nativeElement.value=值;
返回;
}
//从区域设置中得出小数点和千位分隔符
const[thounandseparator,decimalMarker]=formatNumber(1000.99,this.locale)。替换(/\d/g',);
this.decimalMarker=小数标记;
//此处的值应始终随附。作为十进制标记,因此任何其他行为都是错误的
常量[整数,十进制]=值.拆分('.');
//每三个元素分组,并在其后添加千分隔符
this.element.nativeElement.value=integer.replace(/\B(?=(\d{3})+(?!\d))/g,千分位分隔符);
//添加小数和小数标记(如果有)
if(十进制){
this.element.nativeElement.value=this.element.nativeElement.value.concat(十进制标记,十进制);
}
}
私有非匹配值(){
常量值=this.element.nativeElement.value;
if(此.isLastCharacterDecimalSeparator(值)){
返回;
}
const regExp=new regExp(`[^\\d${this.decimalMarker}-]`g');
const[integer,decimal]=value.replace(regExp.),.split(this.decimalMarker);
此._值=整数.concat('.',十进制);
如果(值){
this.element.nativeElement.value=此值;
}否则{
this.element.nativeElement.value='';
}
}
}
要使用此指令,您的html应如下所示:

<mat-form-field>
<mat-label>Value</mat-label>
<input
        type="text"
        localizedNumericInput
        matInput
        autocomplete="off"
        formControlName="value"
      />
</mat-form-field>

价值

ngModelChange每次我更改某些内容时都会发生,例如,我键入1并立即获取1,00,这会干扰我的键入,如果键入1000,则获取1.000。好的,那么它可能不适合您的需要。你一直在做什么
import { Directive, ElementRef, forwardRef, HostListener, Input, OnDestroy } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MAT_INPUT_VALUE_ACCESSOR } from '@angular/material';
import { Subscription } from 'rxjs';
import { formatNumber } from '@angular/common';

@Directive({
  selector: 'input[localizedNumericInput]',
  providers: [
    { provide: MAT_INPUT_VALUE_ACCESSOR, useExisting: LocalizedNumericInputDirective },
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => LocalizedNumericInputDirective),
      multi: true
    }
  ]
})
export class LocalizedNumericInputDirective implements ControlValueAccessor, OnDestroy {
  locale = 'en';
  decimalMarker: string;

  constructor(private element: ElementRef<HTMLInputElement>) {
  }

  private _value: string | null;

  get value(): string | null {
    return this._value;
  }

  @Input('value')
  set value(value: string | null) {
    this._value = value;
    this.formatValue(value);
  }

  @HostListener('input', ['$event.target.value'])
  input(value) {
    //Find all numerics, decimal marker(, or .) and -
    //It will delete thousandSeparator cos it's always opposite to decimal marker
    const regExp = new RegExp(`[^\\d${this.decimalMarker}-]`, 'g');
    //Separate value on before and after decimal marker
    const [integer, decimal] = value.replace(regExp, '').split(this.decimalMarker);

    //Send non localized value, with dot as decimalMarker to API
    this._value = decimal ? integer.concat('.', decimal) : integer;

    // If decimal separator is last character don't update
    // because it will delete . || ,
    if (this.isLastCharacterDecimalSeparator(value)) {
      this._value = value;
    }

    // here to notify Angular Validators
    this._onChange(this._value);
  }

  @HostListener('blur')
  _onBlur() {
    /**
     * Adding thousand separators
     */
    this.formatValue(this._value);
  }

  @HostListener('focus')
  onFocus() {
    this.unFormatValue();
  }

  _onChange(value: any): void {}

  /**
   * @param value
   * apply formatting on value assignment
   */
  writeValue(value: any) {
    this._value = value;
    this.formatValue(this._value);
  }

  registerOnChange(fn: (value: any) => void) {
    this._onChange = fn;
  }

  registerOnTouched() {}

  isLastCharacterDecimalSeparator(value: any) {
    return isNaN(value[value.length - 1]);
  }


  private formatValue(value: string | null) {
    if (value === null) {
      this.element.nativeElement.value = '';
      return;
    }

    if (this.isLastCharacterDecimalSeparator(value)) {
      this.element.nativeElement.value = value;
      return;
    }

    // Conclude the decimal and thousand separators from locale
    const [thousandSeparator, decimalMarker] = formatNumber(1000.99, this.locale).replace(/\d/g, '');
    this.decimalMarker = decimalMarker;

    //Here value should always come with . as decimal marker thus any other behavior is bug
    const [integer, decimal] = value.split('.');

    //Group every three elements, and add thousandSeparator after them
    this.element.nativeElement.value = integer.replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator);

    //Add decimals and decimalMarker if any
    if (decimal) {
      this.element.nativeElement.value = this.element.nativeElement.value.concat(decimalMarker, decimal);
    }
  }

  private unFormatValue() {
    const value = this.element.nativeElement.value;
    if (this.isLastCharacterDecimalSeparator(value)) {
      return;
    }
    const regExp = new RegExp(`[^\\d${this.decimalMarker}-]`, 'g');
    const [integer, decimal] = value.replace(regExp, '').split(this.decimalMarker);

    this._value = integer.concat('.', decimal);
    if (value) {
      this.element.nativeElement.value = this._value;
    } else {
      this.element.nativeElement.value = '';
    }
  }
}
<mat-form-field>
<mat-label>Value</mat-label>
<input
        type="text"
        localizedNumericInput
        matInput
        autocomplete="off"
        formControlName="value"
      />
</mat-form-field>