You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 2实现ng-model输入值货币格式化且保持模型数值型

Angular 2+ 货币格式化输入指令(保持模型数值类型)

我来帮你实现完全符合需求的指令——输入框显示带货币符号的格式化字符串,但绑定的模型值始终保持数值类型,完美解决你之前遇到的服务器加载值后模型变字符串的问题。

指令实现代码

这个指令基于ControlValueAccessor实现,它是Angular表单控件和模型之间的桥梁,能精准控制视图与模型的双向转换:

import { Directive, ElementRef, HostListener, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

@Directive({
  selector: '[appCurrencyInput]',
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CurrencyInputDirective),
      multi: true
    }
  ]
})
export class CurrencyInputDirective implements ControlValueAccessor {
  private onChange: (value: number) => void;
  private onTouched: () => void;
  private element: HTMLInputElement;

  constructor(private el: ElementRef) {
    this.element = el.nativeElement;
  }

  // 模型 → 视图:把数值格式化为带货币符号的两位小数字符串
  writeValue(value: number): void {
    if (value !== null && value !== undefined && !isNaN(value)) {
      this.element.value = `$ ${value.toFixed(2)}`;
    } else {
      this.element.value = '';
    }
  }

  registerOnChange(fn: (value: number) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: () => void): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this.element.disabled = isDisabled;
  }

  // 视图 → 模型:处理用户输入,提取纯数字并转为数值类型
  @HostListener('input', ['$event.target.value'])
  onInput(value: string): void {
    // 过滤掉所有非数字、非小数点的字符
    const numericValue = value.replace(/[^0-9.]/g, '');
    // 处理多个小数点的情况,只保留第一个且最多两位小数
    const parts = numericValue.split('.');
    let cleanValue = parts[0];
    if (parts.length > 1) {
      cleanValue += `.${parts[1].slice(0, 2)}`;
    }
    // 转换为数值(空值则设为null)
    const modelValue = cleanValue ? parseFloat(cleanValue) : null;
    // 更新模型值
    this.onChange(modelValue);
    // 重新格式化输入框显示
    this.writeValue(modelValue);
  }

  // 失去焦点时确保格式规范(比如输入整数自动补两位小数)
  @HostListener('blur')
  onBlur(): void {
    this.onTouched();
    const currentRawValue = this.element.value.replace(/[^0-9.]/g, '');
    if (currentRawValue && !isNaN(parseFloat(currentRawValue))) {
      this.writeValue(parseFloat(currentRawValue));
    }
  }
}

使用步骤

  1. 在模块中声明指令
    把指令添加到你的Angular模块的declarations数组中:

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { FormsModule, ReactiveFormsModule } from '@angular/forms';
    import { CurrencyInputDirective } from './currency-input.directive';
    import { AppComponent } from './app.component';
    
    @NgModule({
      declarations: [AppComponent, CurrencyInputDirective],
      imports: [BrowserModule, FormsModule, ReactiveFormsModule],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    
  2. 在模板中使用
    不管是模板驱动表单还是响应式表单,直接给输入框添加指令即可:

    <!-- 模板驱动表单 -->
    <input type="text" appCurrencyInput [(ngModel)]="productPrice" placeholder="Enter price">
    
    <!-- 响应式表单 -->
    <input type="text" appCurrencyInput formControlName="productPrice" placeholder="Enter price">
    

关键特性说明

  • 模型始终为数值类型:不管是初始赋值(比如从服务器加载的数值)还是用户输入,绑定的模型值都是number类型,不会变成字符串。
  • 自动格式化显示:模型值为2时,输入框显示$ 2.00;用户输入123,失去焦点后自动转为$ 123.00。
  • 输入过滤:自动过滤非数字字符(除了小数点),用户输入$ abc123.456会被处理为$ 123.45,模型值为123.45。
  • 兼容服务器加载场景:当从服务器获取数值赋值给模型时,指令会自动格式化显示,同时保持模型的数值类型。

内容的提问来源于stack exchange,提问作者Saima Gul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 06:43:11