如何仅在视图中保留货币格式而不修改模型值(货币指令)
解决方法:视图显示货币格式,模型保留数字类型
核心思路是分离视图显示值与模型值:仅在输入框中展示格式化后的货币字符串,而模型中始终存储原始数字。这样既满足显示需求,又不影响依赖数字类型的校验逻辑。
修改后的指令实现
import { Directive, ElementRef, Self, AfterViewInit, OnDestroy } from '@angular/core'; import { NgControl } from '@angular/forms'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @Directive({ selector: '[currencyFormatter]' }) export class CurrencyFormatterDirective implements AfterViewInit, OnDestroy { constructor(public el: ElementRef, @Self() private ngControl: NgControl) { this.inputElement = el.nativeElement; this.formatter = new Intl.NumberFormat('en-IN', { style: 'currency', currency: 'INR', minimumFractionDigits: 0, maximumFractionDigits: 0 }); } private formatter: Intl.NumberFormat; private inputElement: HTMLInputElement; private destroy$ = new Subject<boolean>(); ngAfterViewInit(): void { // 初始化时格式化模型初始值 this.formatDisplayValue(this.ngControl.value); // 监听用户输入事件,处理输入内容 this.inputElement.addEventListener('input', this.handleInput.bind(this)); // 监听模型值变化,同步更新视图显示 this.ngControl.control?.valueChanges .pipe(takeUntil(this.destroy$)) .subscribe((value) => { if (value !== this.unformatDisplayValue()) { this.formatDisplayValue(value); } }); } private handleInput(): void { // 解析输入框内容为数字 const rawInput = this.inputElement.value; const numericValue = this.unformatPrice(rawInput); // 更新模型值(确保为数字类型) if (!isNaN(numericValue)) { this.ngControl.viewToModelUpdate(numericValue); } // 重新格式化输入框显示内容 this.formatDisplayValue(numericValue); } private formatDisplayValue(value: number | null | undefined): void { if (value == null || isNaN(value)) { this.inputElement.value = ''; return; } this.inputElement.value = this.formatter.format(value); } private unformatDisplayValue(): number | null { return this.unformatPrice(this.inputElement.value); } private unformatPrice(value: string): number | null { if (!value) return null; // 移除货币符号、逗号等非数字字符 const cleanedValue = value.replace(/[₹$, ]/g, ''); return isNaN(Number(cleanedValue)) ? null : Number(cleanedValue); } ngOnDestroy(): void { this.destroy$.next(true); this.destroy$.complete(); this.inputElement.removeEventListener('input', this.handleInput.bind(this)); } }
关键修改点说明
- 分离视图与模型更新:直接监听输入框的
input事件处理用户输入,仅更新输入框的显示值,通过viewToModelUpdate将解析后的数字同步到模型,确保模型始终存储数字类型。 - 避免循环更新:模型值变化时,仅当模型值与输入框解析后的数字不一致时,才重新格式化显示,防止循环触发更新。
- 健壮的解析逻辑:增强
unformatPrice函数,处理空值、无效字符等场景,避免产生非法数值。 - 兼容外部模型修改:监听模型值变化,确保表单重置、编程式修改模型值时,视图显示能同步更新。
输入元素无需修改
原输入元素的[min]和[max]校验逻辑可继续正常使用,因为模型值始终为数字类型,不受格式化显示的影响。
内容的提问来源于stack exchange,提问作者RAHUL KUNDU
相关产品推荐
相关产品推荐

