16

How do I format the number as I type it in the html input box?

so for example, I want to type the number 2000, the moment I type the 4th digit, the text (that's currently displayed in the textbox) will be automatically formatted to 2,000 (with a comma).

//my modified code based on Moob answer below

<input type="text" class="formattedNumberField" onkeyup="myFunc()">

//jQuery
$(".formattedNumberField").on('keyup', function(){
    var n = parseInt($(this).val().replace(/\D/g,''),10);
    $(this).val(n.toLocaleString());
});

function myFunc(){
// doing something else
}

while this code works perfect as shown in Moob Fiddle, its not working on my end maybe because I have another onkeyup event inside the inputbox???

annamull654
  • 171
  • 1
  • 1
  • 6

5 Answers5

25

Pure JS (Sans jQuery):

var fnf = document.getElementById("formattedNumberField");
fnf.addEventListener('keyup', function(evt){
    var n = parseInt(this.value.replace(/\D/g,''),10);
    fnf.value = n.toLocaleString();
}, false);

Native JS Example Fiddle

With jQuery:

$("#formattedNumberField").on('keyup', function(){
    var n = parseInt($(this).val().replace(/\D/g,''),10);
    $(this).val(n.toLocaleString());
    //do something else as per updated question
    myFunc(); //call another function too
});

With jQuery Example Fiddle

To allow decimals:

$("#formattedNumberField").on('keyup', function(evt){
    if (evt.which != 110 ){//not a fullstop
        var n = parseFloat($(this).val().replace(/\,/g,''),10);
        $(this).val(n.toLocaleString());
    }
});

Obligatory Example

Moob
  • 13,593
  • 1
  • 29
  • 45
  • though the Fiddle works perfect, its not working on my end because I already has an onkeyup that trigers a function in the inputbox. how can I circumvent this? any idea? thanks – annamull654 Oct 19 '13 at 20:50
  • Are you using jQuery or native JS? The most likely solution is to combine the two functions into one. Update your question to include your keyup function (or post a fiddle) – Moob Oct 19 '13 at 20:53
  • I have updated my question above to reflect the changes as per your code. thanks – annamull654 Oct 19 '13 at 21:02
  • Remove the `onkeyup="myFunc()"` from your input box and call `myFunc()` from within the `.on('keyup'` function we created. Like [this](http://jsfiddle.net/LM9zZ/4/) – Moob Oct 19 '13 at 21:10
  • dunno why its still not working. here's my [working example](http://relumastudio.com/aw/) and this is the [fiddle](http://jsfiddle.net/annamull654/3xK4n/4/). my current code breaks if I incorporate our code. – annamull654 Oct 19 '13 at 21:31
  • Woah, that's a lot of code! I see why you were having trouble integrating it. I've cleaned it up a little in [this version](http://jsfiddle.net/3xK4n/8/) – Moob Oct 19 '13 at 22:33
  • 2
    Coool, I think the `input` event could perform much better – kabab Oct 13 '16 at 15:50
  • Nice, yet "allow decimals" won't work if toLocaleString() uses a point as thousands-separator and a comma as decimal separator - in Germany, for example. – BurninLeo May 28 '18 at 12:37
16

With some code bits of other answers I created the following working example. Code is without jquery, but a little bit longer than some other examples. But it takes care of a lot of the problems that others have.

http://jsfiddle.net/kcz4a2ca/10/

Code:

var input = document.getElementById('my_textbox');
var currentValue;

input.addEventListener('input', function(event) {
  var cursorPosition = getCaretPosition(input);
  var valueBefore = input.value;
    var lengthBefore = input.value.length;
  var specialCharsBefore = getSpecialCharsOnSides(input.value);
  var number = removeThousandSeparators(input.value);

  if (input.value == '') {
    return;
  }

  input.value = formatNumber(number.replace(getCommaSeparator(), '.'));

    // if deleting the comma, delete it correctly
  if (currentValue == input.value && currentValue == valueBefore.substr(0, cursorPosition) + getThousandSeparator() + valueBefore.substr(cursorPosition)) {
    input.value = formatNumber(removeThousandSeparators(valueBefore.substr(0, cursorPosition-1) + valueBefore.substr(cursorPosition)));
    cursorPosition--;
  }

  // if entering comma for separation, leave it in there (as well support .000)
  var commaSeparator = getCommaSeparator();
    if (valueBefore.endsWith(commaSeparator) || valueBefore.endsWith(commaSeparator+'0') || valueBefore.endsWith(commaSeparator+'00') || valueBefore.endsWith(commaSeparator+'000')) {
    input.value = input.value + valueBefore.substring(valueBefore.indexOf(commaSeparator));
  }

  // move cursor correctly if thousand separator got added or removed
  var specialCharsAfter = getSpecialCharsOnSides(input.value);
  if (specialCharsBefore[0] < specialCharsAfter[0]) {
        cursorPosition += specialCharsAfter[0] - specialCharsBefore[0];
  } else if (specialCharsBefore[0] > specialCharsAfter[0]) {
        cursorPosition -= specialCharsBefore[0] - specialCharsAfter[0];
  }
  setCaretPosition(input, cursorPosition);

  currentValue = input.value;
});

function getSpecialCharsOnSides(x, cursorPosition) {
    var specialCharsLeft = x.substring(0, cursorPosition).replace(/[0-9]/g, '').length;
  var specialCharsRight = x.substring(cursorPosition).replace(/[0-9]/g, '').length;
  return [specialCharsLeft, specialCharsRight]
}

function formatNumber(x) {
   return getNumberFormat().format(x);
}

function removeThousandSeparators(x) {
  return x.toString().replace(new RegExp(escapeRegExp(getThousandSeparator()), 'g'), "");
}

function getThousandSeparator() {
  return getNumberFormat().format('1000').replace(/[0-9]/g, '')[0];
}

function getCommaSeparator() {
  return getNumberFormat().format('0.01').replace(/[0-9]/g, '')[0];
}

function getNumberFormat() {
    return new Intl.NumberFormat();
}

/* From: http://stackoverflow.com/a/6969486/496992 */
function escapeRegExp(str) {
  return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}

/*
** Returns the caret (cursor) position of the specified text field.
** Return value range is 0-oField.value.length.
** From: http://stackoverflow.com/a/2897229/496992
*/
function getCaretPosition (oField) {
  // Initialize
  var iCaretPos = 0;

  // IE Support
  if (document.selection) {

    // Set focus on the element
    oField.focus();

    // To get cursor position, get empty selection range
    var oSel = document.selection.createRange();

    // Move selection start to 0 position
    oSel.moveStart('character', -oField.value.length);

    // The caret position is selection length
    iCaretPos = oSel.text.length;
  }

  // Firefox support
  else if (oField.selectionStart || oField.selectionStart == '0')
    iCaretPos = oField.selectionStart;

  // Return results
  return iCaretPos;
}

/* From: http://stackoverflow.com/a/512542/496992 */
function setCaretPosition(elem, caretPos) {
    if(elem != null) {
        if(elem.createTextRange) {
            var range = elem.createTextRange();
            range.move('character', caretPos);
            range.select();
        }
        else {
            if(elem.selectionStart) {
                elem.focus();
                elem.setSelectionRange(caretPos, caretPos);
            }
            else
                elem.focus();
        }
    }
}
Patrick Boos
  • 6,131
  • 2
  • 33
  • 36
  • 1
    This is the best answer, doesn't suffer from empty field problem and can edit the number in the middle without losing cursor position. BUT does suffer from characters that are not valid number causing an error instead of just being ignored. – Graham Sep 28 '16 at 13:41
  • How would I do this, only with commas instead of dots as separators? – Tinmar Mar 30 '17 at 13:30
  • I got it - it needed 'en' argument. `Intl.NumberFormat('en');` Also, this is clearly the best answer - it got cursor position problem solved! – Tinmar Mar 30 '17 at 14:42
  • I spent a lot of time looking for an acceptable solution for this, and this is by far the most complete one. – Ivan_nn2 Jun 14 '17 at 07:45
  • how do you add decimal points to this solution? I tried this: `Intl.NumberFormat('en', { maximumFractionDigits: 2 }, { minimumFractionDigits: 2 });` but not working – Ojchris Jan 17 '20 at 17:20
  • the right format is: `Intl.NumberFormat('en', { maximumFractionDigits: 2, minimumFractionDigits: 2 });` – Ojchris Jan 17 '20 at 18:58
  • Finally I found a problem with this script: if you had 100.00 and you try to add an additional 0 to the 100 (or any number with multiple zeros) you end up with a bug like NaN1.000.000.00 rather than 1, 000.00 yet had expected. I found a better solution (though jquery dependent: https://stackoverflow.com/a/50722629/3963837 – Ojchris Jan 17 '20 at 19:08
2

Try this plugin it works pretty nice http://robinherbots.github.io/jquery.inputmask/

krasu
  • 1,957
  • 20
  • 20
  • this is pretty close to what I want. will try it and if it works for me.. I will let you know. thanks – annamull654 Oct 19 '13 at 20:04
  • while this looks promising.. I try to minimize the use of plugins and @Moob demonstrated the perfect example. thanks anyway :) – annamull654 Oct 19 '13 at 20:51
1

You can use ngx-format-field. It is a directive to format the input value which will appear in the view. It will not manipulate the Input value which will be saved in the backend. See link here!

Example:

component.html:

<input type="text" formControlName="currency" [appFormatFields]="CURRENCY"
(change)="onChangeCurrency()">

component.ts

onChangeCurrency() {
this.currency.patchValue(this.currency.value);
}

To see the demo: here!

0

Based on the example you've given, you can use something like this:

$("#my_textbox").keyup(function(){
    if($("#my_textbox").val().length == 4){
        var my_val = $("#my_textbox").val();
        $("#my_textbox").val(Number(my_val).toLocaleString('en'));
    }
});

I used jQuery in the above, but it can be done with pure JS also.

Working example here

Lloyd Banks
  • 32,108
  • 50
  • 143
  • 228