5

I want to format input to USD currency as you type. The input will have 2 decimal places and will enter from right to left. Suppose if I type 54.60 it will be entered as $0.05-->$0.54-->$5.46-->$54.60. This PLUNKER exactly does this, but its in angular js. So far my directive looks like:

import {Directive, Output, EventEmitter} from '@angular/core';
import {NgControl} from '@angular/forms';

@Directive({
  selector: '[formControlName][currency]',
  host: {
    '(ngModelChange)': 'onInputChange($event)',
    '(keydown.backspace)':'onInputChange($event.target.value, true)'
  }
})
export class CurrencyMask {
  constructor(public model: NgControl) {}

  @Output() rawChange:EventEmitter<string> = new EventEmitter<string>();

  onInputChange(event: any, backspace: any) {
    // remove all mask characters (keep only numeric)
    var newVal = event.replace(/\D/g, '');
    var rawValue = newVal;
    var str = (newVal=='0'?'0.0':newVal).split('.');
    str[1] = str[1] || '0';
    newVal= str[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') + '.' + (str[1].length==1?str[1]+'0':str[1]);



    // set the new value
    this.model.valueAccessor.writeValue(newVal);
    this.rawChange.emit(rawValue)
  }
}

and in html it is being used as:

<input  name="cost" placeholder="cost" class="form-control"  type="text" currency formControlName="cost" (rawChange)="rawCurrency=$event">

Update:

what finally worked for me is:

onInputChange(event: any, backspace: any) {
    var newVal = (parseInt(event.replace(/[^0-9]/g, ''))/100).toLocaleString('en-US', { minimumFractionDigits: 2 });
    var rawValue = newVal;

    if(backspace) {
      newVal = newVal.substring(0, newVal.length - 1);
    }

    if(newVal.length == 0) {
      newVal = '';
    }
    else  {
      newVal = newVal;
    }
    // set the new value
    this.model.valueAccessor.writeValue(newVal);
    this.rawChange.emit(rawValue)
  }
Jane
  • 283
  • 3
  • 5
  • 16

2 Answers2

3

on input change use the following

// remove dot and comma's, 123,456.78 -> 12345678
var strVal = myVal.replace(/\.,/g,'');
// change string to integer
var intVal = parseInt(strVal); 
// divide by 100 to get 0.05 when pressing 5 
var decVal = intVal / 100;
// format value to en-US locale
var newVal = decVal.toLocaleString('en-US', { minimumFractionDigits: 2 });

// or in singel line
var newVal = (parseInt(myVal.replace(/\.,/g, '')) / 100).toLocaleString('en-US', { minimumFractionDigits: 2 });

or

use currency pipe to format to USD format by using only

var newVal = (parseInt(myVal.replace(/\.,/g, '')) / 100)

Hope this helps.

hakany
  • 7,134
  • 2
  • 19
  • 22
  • it's only allowing me to type 1 digit at a time, if I type7 then it shows 0.07; then if I type 8 it makes it 0...it keeps acting in this way – Jane Feb 07 '17 at 14:55
  • I assume you are getting the char from the event, in that case you need to append the new char at the end of strVal. the best way (of course this is my opinion) would be to use two way binding in angular2 whereby the input is updated with ngModel and update that variable after each keypress – hakany Feb 07 '17 at 15:04
  • var newVal = (parseInt(myVal.replace(/\.,/g, '') + newChar) / 100).toLocaleString('en-US', { minimumFractionDigits: 2 }); – hakany Feb 07 '17 at 15:15
0

Angular has a formatCurrency method

https://angular.io/api/common/formatCurrency

Here's how I've used it in my code:

demand is a formControl

formatMoney(value: string) {
    this.demand.setValue(
        this.formatMoneyBase(value)
    );
}

formatMoneyBase(value: string = ''): string {
    return value.length ? formatCurrency(parseFloat(value.replace(/\D/g, '')), 'en', '$').replace('$', '') : '';
}
Paul Story
  • 582
  • 4
  • 10