Angular中如何为ngModel绑定的数值添加两位小数显示?
问题描述
有一个绑定数值类型变量sipmaximum的输入框,当前显示示例为9999,需要将其格式化为9999.00的格式展示。相关代码如下:
模板代码
<tr> <th>SIP maximum </th> <td> <input id="sipmaximum" name="sipmaximum" type="text" class="form-control" [(ngModel)]="sipmaximum" style="width: 70%" required greaterThanZero /> </td> </tr>
JSON数据
{ "AANBOD": { "ISINAANBOD": "Y", "RISK": "3", "COMMENTAIRE_FR": "", "COMMENTAIRE_NL": "", "QTTE_TOTALE": 0, "QTTE_FAITE": 0, "QTTE_REST": 0, "QTTE_MIN": 100, "QTTE_MAX": 15000, "MULTIPLE": 0, "DATEVALID_DEBUT": "2019-09-16", "DATEVALID_FIN": "2050-12-31", "MARKET": "", "SIPAGENCEFLAG": "Y", "SIPCLIENTFLAG": "N", "SIPMINIMUM": 50, "SIPMAXIMUM": 9999 } }
组件代码
export class EditPurchasableSecuritiesComponent implements OnInit, OnDestroy { private unsubscribe$ = new Subject<void>(); svm: string; risk: string; datedeb: Date; datefin: Date; min: number; max: number; sipminimum: number; sipmaximum: number; TIT: Tit[] = []; constructor( private service: EditPurchasableSecuritiesService, private activatedRoute: ActivatedRoute, private location: Location, private router: Router ) {} ngOnInit(): void { let svm: string | null; svm = this.activatedRoute.snapshot.paramMap.get("svm"); if (!svm) { this.goBack(); return; } this.svm = svm; this.editPurchasableSecuritiesManagement(this.svm); this.datedeb = new Date(); } ngOnDestroy(): void { this.unsubscribe$.next(); this.unsubscribe$.complete(); } editPurchasableSecuritiesManagement(svm: string): void { this.service .editPurchasableSecuritiesManagement(this.svm) .pipe(takeUntil(this.unsubscribe$)) .subscribe((res) => { if (res.RETURNCODE === ApiResponseCodeEnum.Ok) { this.TIT = res.TIT; this.risk = res.TIT[0].AANBOD.RISK; this.datedeb = new Date(); this.datefin = new Date(res.TIT[0].AANBOD.DATEVALID_FIN); this.min = res.TIT[0].AANBOD.QTTE_MIN; this.max = res.TIT[0].AANBOD.QTTE_MAX; this.sipminimum = res.TIT[0].AANBOD.SIPMINIMUM; this.sipmaximum = res.TIT[0].AANBOD.SIPMAXIMUM; } }); } goBack(): void { this.location.back(); } updatePurchasableSecuritiesManagement(): void { this.service .updatePurchasableSecuritiesManagement( this.svm, this.risk, this.datedeb, this.datefin, this.min, this.max, this.sipminimum, this.sipmaximum ) .pipe(takeUntil(this.unsubscribe$)) .subscribe((res) => { if (res.RETURNCODE === ApiResponseCodeEnum.Ok) { this.router .navigateByUrl("/", { skipLocationChange: true }) .then(() => { this.router.navigate([ "functional-management/list-purchasable-securities", ]); }); } }); } }
接口定义
export interface PurchasableSecuritieResponse extends ApiResponse { TIT: Tit[]; } export interface Tit { ADVTITRE: { BASIQUETITRE: { SVM: number; ISIN: string; STOCK: string; LABEL: string; PLACE: number; PLACELABEL: string; REGR: number; REGRLABEL: string; DEVISE: string; COURS: { DATE: string; TIME: string; VALUE: number; HIGH: number; LOW: number; CLOTURE: number; }; }; EXIST: number; SECE: number; SECE_LIB: string; PAYS: number; PAYS_LIB: string; YPMAR: string; CUM: string; DEVCP: string; CPPX: number; DATCPN: string; COURG: number; DCOURG: string; COURB: number; DCOURB: string; CODEF: number; ECHEANCE: string; RADIATION: string; COTATION: string; RATING: string; COURUS: number; BRUT: number; ECH1: string; ECH2: string; ECH3: string; ECH4: string; ECH5: string; TAUX1: number; TAUX2: number; TAUX3: number; TAUX4: number; TAUX5: number; HYPERLINK: string; INFOBOU: number; HISTCOURS: number; GROUPE: string; COUPON: number; WARRANT: number; OPTION: number; REVERSE: number; RECO: number; SIGNAUX: number; }; TITARG: { COMPLEXITY: string; CREATTIME: string; CREATUSER: string; MODTIME: string; MODUSER: string; CREATMODE: string; }; AANBOD: { ISINAANBOD: string; RISK: string; COMMENTAIRE_FR: string; COMMENTAIRE_NL: string; QTTE_TOTALE: number; QTTE_FAITE: number; QTTE_REST: number; QTTE_MIN: number; QTTE_MAX: number; MULTIPLE: number; DATEVALID_DEBUT: Date; DATEVALID_FIN: Date; MARKET: string; SIPAGENCEFLAG: string; SIPCLIENTFLAG: string; SIPMINIMUM: number; SIPMAXIMUM: number; PRIX_MARCHE: number; PRIX_CLIENT: number; }; ...
解决方案
因为输入框是双向绑定的数值类型,要实现显示为9999.00格式,同时保证用户输入后能正确转换回数值类型,可采用以下几种方式:
方法一:使用DecimalPipe拆分双向绑定
利用Angular内置的DecimalPipe格式化显示,拆分双向绑定为单向绑定和输入事件,分别处理显示与值更新:
- 组件中注入
DecimalPipe:
import { DecimalPipe } from '@angular/common'; // ... constructor( // 其他依赖 private decimalPipe: DecimalPipe ) {}
- 修改模板,拆分
[(ngModel)]:
<tr> <th>SIP maximum </th> <td> <input id="sipmaximum" name="sipmaximum" type="text" class="form-control" [ngModel]="decimalPipe.transform(sipmaximum, '1.2-2')" (ngModelChange)="onSipMaximumChange($event)" style="width: 70%" required greaterThanZero /> </td> </tr>
'1.2-2'表示最少1位整数、固定2位小数。
- 组件中添加输入转换方法:
onSipMaximumChange(value: string): void { // 过滤非数字和小数点字符,转换为数值 const numericValue = parseFloat(value.replace(/[^0-9.]/g, '')) || 0; this.sipmaximum = numericValue; }
方法二:自定义双向绑定指令(复用场景)
如果需要在多个组件中复用该格式化逻辑,可自定义指令:
- 创建
NumberFormatDirective指令:
import { Directive, ElementRef, HostListener, forwardRef } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { DecimalPipe } from '@angular/common'; @Directive({ selector: '[appNumberFormat]', providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NumberFormatDirective), multi: true } ] }) export class NumberFormatDirective implements ControlValueAccessor { private onChange: (value: number) => void; private onTouched: () => void; constructor( private el: ElementRef, private decimalPipe: DecimalPipe ) {} writeValue(value: number): void { // 格式化数值并显示 const formattedValue = this.decimalPipe.transform(value, '1.2-2'); this.el.nativeElement.value = formattedValue || ''; } registerOnChange(fn: (value: number) => void): void { this.onChange = fn; } registerOnTouched(fn: () => void): void { this.onTouched = fn; } @HostListener('input', ['$event.target.value']) onInput(value: string): void { // 转换输入为数值 const numericValue = parseFloat(value.replace(/[^0-9.]/g, '')) || 0; this.onChange(numericValue); // 重新格式化确保显示格式正确 this.el.nativeElement.value = this.decimalPipe.transform(numericValue, '1.2-2'); } @HostListener('blur') onBlur(): void { this.onTouched(); } }
- 在模块中声明指令后,模板中直接使用:
<input id="sipmaximum" name="sipmaximum" type="text" class="form-control" [(ngModel)]="sipmaximum" appNumberFormat style="width: 70%" required greaterThanZero />
方法三:组件内直接处理(简单场景)
仅在当前组件使用时,可直接在组件内拆分显示与存储变量:
- 新增显示用字符串变量:
sipmaximum: number; sipmaximumDisplay: string; // 存储格式化后的显示值
- 获取接口数据时格式化赋值:
editPurchasableSecuritiesManagement(svm: string): void { this.service .editPurchasableSecuritiesManagement(this.svm) .pipe(takeUntil(this.unsubscribe$)) .subscribe((res) => { if (res.RETURNCODE === ApiResponseCodeEnum.Ok) { // ...其他变量赋值 this.sipmaximum = res.TIT[0].AANBOD.SIPMAXIMUM; // 格式化为两位小数的字符串 this.sipmaximumDisplay = this.sipmaximum.toFixed(2); } }); }
- 修改模板绑定显示变量,添加失焦转换逻辑:
<input id="sipmaximum" name="sipmaximum" type="text" class="form-control" [(ngModel)]="sipmaximumDisplay" (blur)="onSipMaximumBlur()" style="width: 70%" required greaterThanZero />
- 组件中添加失焦转换方法:
onSipMaximumBlur(): void { const numericValue = parseFloat(this.sipmaximumDisplay.replace(/[^0-9.]/g, '')) || 0; this.sipmaximum = numericValue; // 重新格式化确保显示正确 this.sipmaximumDisplay = numericValue.toFixed(2); }
内容的提问来源于stack exchange,提问作者MarinaLaGrande
相关产品推荐
相关产品推荐

