【问题标题】:Angular 8 custom currency maskAngular 8 自定义货币掩码
【发布时间】:2019-06-17 20:20:46
【问题描述】:

现在我正在制作一个应该与角度反应形式兼容的货币掩码指令。这是我的 Stackblitz https://stackblitz.com/edit/angular-8-currency-directive-insert

在输入元素中,我希望当我输入 1、2、3、4、5 时,我会在控制台中看到 {currency: "$1,234"} 因为掩码运行 .substring(0, 4) 但是我看到 {currency: "$1,2345"}。 我在输入元素中看到正确的显示值为 $1,234。

如果我将 .substring(0,4) 更改为 .substring(0,3),则输入元素中的显示值显示为 $1,23,而我希望它显示为 $1,234。控制台输出正确的 {currency: "$1,234"}

非常欢迎任何能找到问题根源的建议!我已经完成了一些工作,包括拆分成一个数组、检查、弹出末端和加入,但这些修复并不理想。不过,仍然欢迎任何建议!

感谢您的支持。

要关注的代码在下面提供的 currency.directive.ts 中:

 onInputChange(event, backspace) {
    let newVal = event.replace(/\D/g, '');
    if (newVal.length === 0) {
      newVal = '';
    } else if (newVal.length <= 3) {
      newVal = newVal.replace(/^(\d{0,3})/, '$1');
    // } else if (newVal.length <= 4) {
    //   newVal = newVal.replace(/^(\d{0,1})(\d{0,3})/, '$1,$2');
    } else {
      newVal = newVal.substring(0, 4);
      newVal = newVal.replace(/^(\d{0,1})(\d{1,3})/, '$1,$2');
    }
    this.ngControl.valueAccessor.writeValue("$"+ newVal);
    // console.log(this.toNumber(newVal))
  }

【问题讨论】:

  • 在我写答案之前,我需要问一下,您是否评估过 Angular 的内置 currencyPipe.transform(numberValue, 'USD', 'symbol', '1.0')
  • 我认为你做错了,检查blog.thoughtram.io/angular/2016/07/27/…
  • 如果您有文档重新分级您正在使用的方法,请分享
  • 嗨@BenRacicot,谢谢。是的,我们对此进行了调查,但发现它不符合我们的要求,因此决定采用这种方法,该方法仅具有上面指定的最后一个要求。我也在 stackblitz 上留下了一些 cmets。
  • 我正在努力,是的,我确实看到 CurrencyPipe 有很多不足之处。

标签: regex angular typescript angular-reactive-forms


【解决方案1】:

您的问题启发了我创建一个可以使用的 CurrencyDirective。它不会像您那样处理这种情况,但我相信它可以被用来代替或希望帮助他人。

StackBlitz - Currency Format Directive

原因:

  • 我们不应该在我们的价值中加入货币符号$1,234
  • 我们应该格式化为用户类型(无痛用户体验)
  • 我们应该将我们的货币价值保存为原始数字(带 格式)
  • 我们不应该对 3 个字符、4 个字符、5 个字符等进行正则表达式来有条件地添加格式(逗号或点)

这就是我所做的。 我处理pasteinputdrop 事件,但格式化是在getCurrencyFormat() 内完成的:

getCurrencyFormat(val) {
    // 1. test for non-number characters and replace/remove them
    const filtered = parseInt(String(val).replace(this.currencyChars, ''));

    // 2. format the number (add commas)
    const usd = this.decimalPipe.transform(filtered, '1.0');

    // 3. replace the input value with formatted numbers
    this.renderer.setProperty(this.el.nativeElement, 'value', usd);
}

我认为应该以原始数字来节省货币。所以在提交表单时我这样做:

Number(this.form.get('currency').value.replace(/[^0-9]g/, ''));

【讨论】:

  • stackblitz.com/edit/currency-format-directive-achp8p?file=src/… 你的代码没有按预期工作,输入内部的值和它外部的值不一样,例如写 12345678,在输入内部它将是 1,234,但是外面是 1,234,5678
  • 抱歉没注意到
  • 如果你知道为什么请告诉我
  • @Robert 我修好了。这是一个缺少g 标志的简单正则表达式问题。我很想听听你对此的看法。
  • @BenRacicot 顺便说一句,我认为你所做的令人印象深刻。 Angular 应该采用这个
【解决方案2】:

Stackblitz https://stackblitz.com/edit/angular-8-currency-directive-insert-jdwx4b

货币自定义输入

import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
  selector: 'app-currency',
  template: '<input [(ngModel)]="value" (keyup)="setValue(value)">',
  styleUrls: ['./currency.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CurrencyComponent),
      multi: true
    }
  ]
})
export class CurrencyComponent implements ControlValueAccessor {

  value;

  constructor() {
  }

  setValue(event) {
    let newVal = event.toString().replace(/\D/g, '');
    if (newVal.length === 0) {
      newVal = '';
    } else if (newVal.length <= 3) {
      newVal = newVal.replace(/^(\d{0,3})/, '$1');
    } else {
      newVal = newVal.substring(0, 4);
      newVal = newVal.replace(/^(\d{0,1})(\d{1,3})/, '$1,$2');
    }
    newVal = '$' + newVal;
    if (newVal) {
      this.value = newVal;
      setTimeout(() => {
        // sometimes it needs a tick, specially first time
        this.propagateChange(this.value);
      });
    }
  }

  writeValue(value: any) {
    if (value !== undefined) {
      this.setValue(value);
    }
  }

  registerOnChange(fn) {
    this.propagateChange = fn;
  }

  registerOnTouched() {
  }

  propagateChange = (_: any) => {
  }

}

用法

<app-currency formControlName="currency"></app-currency>

【讨论】:

  • 谢谢罗伯特!不幸的是 ngModel 已被弃用:(
  • 什么意思?
  • @immickvaughn 我用谷歌搜索了它,发现只有当你将它与反应形式一起使用时,ngmodel 才会被弃用,而且将我的解决方案重写为反应形式并不难
  • 好的,我现在可以看到了。如果您只想用 stackblitz 中的解决方案替换以前的解决方案,我会将其标记为已回答。谢谢楼主
  • 谢谢!你知道为什么长度从不为0吗?反应式表单验证(必需)不起作用......很奇怪它总是会保留最后一个值。所以我也尝试删除最后一个值,但经过一系列尝试,我无法做到。我试图在主机侦听器事件中获取退格字符代码,当长度为 1 并按下退格键时,将输入值设置为空字符串。这对我不起作用。stackblitz.com/edit/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-31
  • 1970-01-01
  • 1970-01-01
  • 2010-11-15
  • 2023-03-17
相关资源
最近更新 更多