I am working on an Angular project and I have an object of type Project that contains the following values:
cost: 56896 and costHR: 27829
I want to modify the object using a form and bind the fields with ngModel to the attributes.
But the problem I am facing is that in the field, I want to display the number in a currency format (e.g. 56,896€) which is not compatible with the variable type which is float.
Can someone help me with a solution to this problem? I have tried using built-in Angular pipes and custom formatter and parser functions, but none of them seem to work as expected.
Any help would be greatly appreciated.
import { Component, OnInit } from '@angular/core';
import { CurrencyPipe } from '@angular/common';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [CurrencyPipe]
})
export class AppComponent implements OnInit {
project = {
cost: 56896,
costRH: 27829
}
constructor(private currencyPipe: CurrencyPipe) { }
ngOnInit() {
this.project.cost = this.currencyPipe.transform(this.project.cost, 'EUR', 'symbol', '1.0-0');
this.project.costRH = this.currencyPipe.transform(this.project.costRH, 'EUR', 'symbol', '1.0-0');
}
onBlur(event, projectProperty) {
this.project[projectProperty] = this.currencyPipe.parse(event.target.value);
}
}
<form>
<label for="cost">Cost</label>
<input [(ngModel)]="project.cost" (blur)="onBlur($event, 'cost')" [ngModelOptions]="{updateOn: 'blur'}" [value]="project.cost | currency:'EUR':'symbol':'1.0-0'">
<label for="costRH">Cost RH</label>
<input [(ngModel)]="project.costRH" (blur)="onBlur($event, 'costRH')" [ngModelOptions]="{updateOn: 'blur'}" [value]="project.costRH | currency:'EUR':'symbol':'1.0-0'">
</form>
What I expected: I expected the input fields to be formatted as currency (e.g. 56,896€) and for the corresponding properties in the 'projet' object (cost and costRH) to be updated with the parsed value when the input loses focus.
What happened instead: The value displayed in the input fields is not formatted as currency and the corresponding properties in the object are not being updated as expected.
you can use a directive like
@Directive({
selector: '[format]',
})
export class FormatDirective implements OnInit {
format = 'N0';
digitsInfo = '1.0-0';
@Input() currency = '$';
@Input() suffix = '';
@Input() decimalCharacter = null;
@Input('format') set _(value: string) {
this.format = value;
if (this.format == 'N2') this.digitsInfo = '1.2-2';
const parts = value.split(':');
if (parts.length > 1) {
this.format = value[0];
this.digitsInfo = parts[1];
}
}
@HostListener('blur', ['$event.target']) blur(target: any) {
target.value = this.parse(target.value);
}
@HostListener('focus', ['$event.target']) focus(target: any) {
target.value = this.control.value;
}
ngOnInit() {
setTimeout(() => {
this.el.nativeElement.value = this.parse(this.el.nativeElement.value);
});
}
constructor(
@Inject(LOCALE_ID) private locale: string,
private el: ElementRef,
private control: NgControl
) {}
parse(value: any) {
let newValue = value;
if (this.format == 'C2')
newValue = formatCurrency(value, this.locale, this.currency);
if (this.format == 'N2')
newValue = formatNumber(value, this.locale, this.digitsInfo);
if (this.format == 'N0')
newValue = formatNumber(value, this.locale, this.digitsInfo);
if (this.format == 'NX')
newValue = formatNumber(value, this.locale, this.digitsInfo);
if (this.decimalCharacter)
return (
newValue.replace('.', 'x').replace(',', '.').replace('x', ',') +
this.suffix
);
return newValue + this.suffix;
}
}
Works like
<input format="N0" [(ngModel)]="value"/>
<input format="N2" [(ngModel)]="value"/>
<input format="C2" [(ngModel)]="value"/>
<input format="N2" decimalCharacter='.' suffix=' €' [(ngModel)]="value"/>
The idea of the directive is that, when blur, change the "native Element", but not the value of the ngControl, when focus return the value of the ngControl
The stackblitz