javascriptangularangular-directive

How can i format input fields as currency in Angular


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.


Solution

  • 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