2

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.

2
  • Does this answer your question? html5 input for money/currency Commented Jan 26, 2023 at 6:51
  • I would create a separate <span class="currency">{{ currency }}</span> next to the number input field and I would overlay them witch CSS. (put span over number input) Ofc make sure with paddings that the number isn't blocked out by the new span. (Also, you should probably try using some localization library) Commented Jan 26, 2023 at 6:56

2 Answers 2

5

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

Sign up to request clarification or add additional context in comments.

Comments

0

I have used Numberal js for formatting numbers and it was awesome

Your desired format is this one '0,0[.]00 €'

check docs

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.