我有一个输入字段,想要使用德语语言环境输入一个浮点数。我的解决方案如下,它可以工作,但是很复杂,应该有更好的方法吗?
<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);
}
答案 0 :(得分:3)
我在格式化反应形式输入字段时遇到了类似的问题。为了解决这个问题,我使用了这个article。我创建了一个略微修改的版本以满足我的需求。
disposable.add(module.getInfo()
.flatMapSingleElement {
profile ->
profile.getDetails().map {
//IS THIS NEW DISPOSABLE NEEDED
newDisposable.add(
//Retrofit api to return Single<ResponseBody>
//IS THIS THE RIGHT WAY TO MAKE A SEQUENTIAL API CALL IN RX CONSUMING DATA FROM ANOTHER OPERATOR
module.saveImageDetails(
ImageDetails(imageId)
subscribeOn(Schedulers.io().observeOn(Schedulers.io())
.subscribe(
Consumer { handleResponse(it) },
createErrorHandler()
)
)
profile
}
}
.subscribeOn(ioScheduler)
.observeOn(uiScheduler)
.subscribe(//do something)
要使用此指令,您的html应该如下所示:
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 = '';
}
}
}
答案 1 :(得分:1)
是的,这部分有些棘手。此外,有时您需要显示的不是实际值。
我发现它是为我的输入创建一个自定义组件(使用ngModel,请参阅有关ControlValueAccessor的方法)的实际最佳解决方案,它看起来像是基于您要执行的操作。
html:
<input [formControl]="inputFormControl" #myInput />
ts:
@ViewChild('myInput') inputElm: ElementRef;
formGroup: FormGroup;
value: number;
this.inputFormControl.valueChanges.subscribe((value: string) => {
if (value) {
const displayValue = ('' + value).replace(',', '.');
this.value = parseFloat(displayValue); // manage the value
this.inputFormControl.setValue(this.value, { emitEvent: false });
this.inputElm.nativeElement.value = new DecimalPipe(this.localId).transform(displayValue, '0.2-2'); //control the display
}
});
从某种意义上讲,您一定会发现它有些复杂,但是最后它还为您提供了更多的控制权;)
答案 2 :(得分:0)
您的方法很好。
没有比将input
的数据从变量转换为Pipe
更好的方法,没有比绑定到DOM事件的函数更好的将数据从input
转换为变量的方法。
为了简化代码,您可以执行以下操作:
<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);
}
答案 3 :(得分:0)
我使用这篇Angular 2 Directives to Format Text as you Type文章中的信息创建了一个指令。
它正在工作,但是我不明白为什么必须要有'Change'后缀,以及为什么我不能从行中将输入与事件分开:(appNumberInput)= .... [appNumberInput] = ...
<input [(appNumberInput)]="amount" format="0.2-2" />
@Directive({
selector: '[appNumberInput]',
})
export class NumberInputDirective implements OnInit {
@Input()
appNumberInput: any;
@Input()
format: string;
@HostBinding('value')
stringValue: string;
@Output() appNumberInputChange: EventEmitter = new EventEmitter();
constructor(private decimalPipe: DecimalPipe) {
}
ngOnInit() {
this.stringValue = this.decimalPipe.transform(this.appNumberInput, this.format);
}
@HostListener('blue', ['$event.target.value'])
@HostListener('keyup.enter', ['$event.target.value'])
formatANumber(value) {
const numberValue = parseFloat(value.replace('.', '').replace(',', '.'));
this.stringValue = this.decimalPipe.transform(numberValue, this.format);
this.appNumberInputChange.next(numberValue);
}
}