1

I have a text input where I want it to format while typing a value allowing 2 decimal places and 1000 separators. It should only allow digits. I have done the following but it does not allow adding decimal points. Simply put it is for entering the price of a product (currency).

INPUT = 1234560ABC.5665 (should only allow numbers)

EXPECTED = 1,234,560.56 (should limit decimal places to 2)

I have done the following but no idea how to add decimal values followed by a "." securing the "," 1000 separators.

<input type="text" id="price" name="price" />

$('#price').keyup(function (event) {
    $(this).val(function (index, value) {
        return '$' + value.replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    });
});
Community
  • 1
  • 1
Teshan N.
  • 2,307
  • 3
  • 30
  • 59
  • 1
    Don't forget to accept the answer you think it's right. We are expecting this from you. Don't just ask and go away. – Taha Paksu Apr 05 '18 at 06:06

3 Answers3

15

My solution uses successive .replace

  1. .replace(/(?!\.)\D/g, "") deletes all non numeric characters except .
  2. .replace(/(?<=\..*)\./g, "") removes all extra . except the first .
  3. .replace(/(?<=\.\d\d).*/g, "") deletes everything after 2 decimal places
  4. .replace(/\B(?=(\d{3})+(?!\d))/g, ",") inserts commas at appropriate places

I have modified the event to account for all changes to input field as .on('change click keyup input paste'

Snippet:

$('#price').on('change click keyup input paste',(function (event) {
    $(this).val(function (index, value) {
        return '$' + value.replace(/(?!\.)\D/g, "").replace(/(?<=\..*)\./g, "").replace(/(?<=\.\d\d).*/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    });
}));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<input type="text" id="price" name="price" />
Abdul Hameed
  • 1,025
  • 12
  • 27
  • @TechyTee what is not working ? what input you tried which failed? – Abdul Hameed Apr 03 '18 at 07:50
  • @TechyTee Updated the answer with another variant. check it. – Abdul Hameed Apr 03 '18 at 07:58
  • Still not working. The snippet gives an error. I only entered numbers. Nothing happened. Error: { "message": "SyntaxError: invalid regexp group", "filename": "https://stacksnippets.net/js", "lineno": 16, "colno": 60 } – Teshan N. Apr 03 '18 at 08:13
  • It looks good for me, when I write letter I have nothing, when I write number I have `$XX,XXX,XXX`, if I add a `.` I have only one and only 2 number after, that's not what OP wanted? – Mickaël Leger Apr 03 '18 at 08:33
  • @TechyTee https://jsfiddle.net/xpvt214o/31495/ try the same script here in fiddle – Abdul Hameed Apr 03 '18 at 10:08
  • @MickaelLeger **EXPECTED = 1,234,560.56 (should limit decimal places to 2)** decimal place limitations is there in OP's question – Abdul Hameed Apr 03 '18 at 10:09
  • @TechyTee provide us more test cases if you want correct solution. – Abdul Hameed Apr 03 '18 at 10:13
  • 1
    This answer is underrated. I found a lot of answers that were close to what I wanted but not quite there. This one does exactly what I'm looking for. – Sarah Cox Mar 31 '21 at 14:40
  • 1
    This answer does work, but I was getting a "invalid regular expression invalid group specifier name" in Safari. I believe this is due to Safari not supporting the Lookbehind 2018 JS Standard in Regex found here - https://caniuse.com/js-regexp-lookbehind - and another answer addresses this here - https://stackoverflow.com/questions/51568821/works-in-chrome-but-breaks-in-safari-invalid-regular-expression-invalid-group - nothing wrong with the answer, just beware. – RCNeil Sep 13 '22 at 20:03
4

You can limit the keys in the keydown event instead of keyup and allow specific keys to take effect, and then format the input on keyup event:

$("#testinput").on("keydown", function(e) {
  var keycode = (event.which) ? event.which : event.keyCode;
  if (e.shiftKey == true || e.ctrlKey == true) return false;
  if ([8, 110, 39, 37, 46].indexOf(keycode) >= 0 || // allow tab, dot, left and right arrows, delete keys
    (keycode == 190 && this.value.indexOf('.') === -1) || // allow dot if not exists in the value
    (keycode == 110 && this.value.indexOf('.') === -1) || // allow dot if not exists in the value
    (keycode >= 48 && keycode <= 57) || // allow numbers
    (keycode >= 96 && keycode <= 105)) { // allow numpad numbers
    // check for the decimals after dot and prevent any digits
    var parts = this.value.split('.');
    if (parts.length > 1 && // has decimals
      parts[1].length >= 2 && // should limit this
      (
        (keycode >= 48 && keycode <= 57) || (keycode >= 96 && keycode <= 105)
      ) // requested key is a digit
    ) {
      return false;
    } else {
      if (keycode == 110) {
        this.value += ".";
        return false;
      }
      return true;
    }
  } else {
    return false;
  }
}).on("keyup", function() {
  var parts = this.value.split('.');
  parts[0] = parts[0].replace(/,/g, '').replace(/^0+/g, '');
  if (parts[0] == "") parts[0] = "0";
  var calculated = parts[0].replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
  if (parts.length >= 2) calculated += "." + parts[1].substring(0, 2);
  this.value = calculated;
  if (this.value == "NaN" || this.value == "") this.value = 0;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="testinput">
Taha Paksu
  • 15,371
  • 2
  • 44
  • 78
2
$('#price').on('keyup click change paste input', function (event) {
    $(this).val(function (index, value) {
        if (value != "") {
            //return '$' + value.replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",");
            var decimalCount;
            value.match(/\./g) === null ? decimalCount = 0 : decimalCount = value.match(/\./g);

            if (decimalCount.length > 1) {
                value = value.slice(0, -1);
            }

            var components = value.toString().split(".");
            if (components.length === 1)
                components[0] = value;
            components[0] = components[0].replace(/\D/g, '').replace(/\B(?=(\d{3})+(?!\d))/g, ',');
            if (components.length === 2) {
                components[1] = components[1].replace(/\D/g, '').replace(/^\d{3}$/, '');
            }

            if (components.join('.') != '')
                return '$' + components.join('.');
            else
                return '';
        }
    });
});
Teshan N.
  • 2,307
  • 3
  • 30
  • 59
  • in your code when i'm entering second decimal place, it is truncating all decimal places. is this what you wanted..? – Abdul Hameed Apr 03 '18 at 12:00