16

I've walked into a strange problem. When trying to replace a dot on a number input, instead of replacing just that dot, it clears out the entire input.

$("[data-input-payment-id]").on("keyup", function(e) {
  var test_value = $(this).val().replace(/\./g, "");
  $(this).val(test_value);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" data-input-payment-id="12">

JSFIDDLE

How do I change it so it only removes the dots?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ellisan
  • 563
  • 8
  • 22
  • 6
    works fine in firefox and chrome and edge - and you can't be using internet explorer, because then you wouldn't be using jsfiddle – Jaromanda X Jul 30 '18 at 09:49
  • though, in firefox, if you press **and hold** `.` then you get what you describe – Jaromanda X Jul 30 '18 at 09:52
  • 2
    @JaromandaX seems to break if you type 2 dots in a row – Pete Jul 30 '18 at 09:52
  • nope, only press and hold or type several very quickly – Jaromanda X Jul 30 '18 at 09:53
  • 6
    @JaromandaX im testing this in chrome and it does NOT work for me – Ellisan Jul 30 '18 at 09:53
  • oh, right, yes, chrome if you do two `.` in a row ... chrome is weird – Jaromanda X Jul 30 '18 at 09:54
  • Seems it is related to `input type="number"`. Change it to `text` and it works. – connexo Jul 30 '18 at 10:01
  • @connexo i would but i need to use number – Ellisan Jul 30 '18 at 10:02
  • 2
    Looks like if you use an invalid number in type = number, `this.value` will return a blank string - maybe connected: https://stackoverflow.com/questions/18677323/html5-input-type-number-value-is-empty-in-webkit-if-has-spaces-or-non-numeric-ch - instead of removing the dots, why not just prevent them from typing the dots – Pete Jul 30 '18 at 10:03
  • $(this).val().split('.').join(' '); – NullPointer Jul 30 '18 at 10:03
  • I can solve firefox - but chrome ... you type `123.` ... wait, nothing changes ... type a number, and bang ...the `.` disappears! how odd is chrome! the keyup event doesn't fire on the first `.` – Jaromanda X Jul 30 '18 at 10:06
  • @Ellisan - you fail to mention in your question that this occurs in chrome when typing two consecutive `.` – Jaromanda X Jul 30 '18 at 10:09
  • related: [How to get the raw value an `` field?](https://stackoverflow.com/questions/18852244/how-to-get-the-raw-value-an-input-type-number-field) – Bergi Jul 30 '18 at 20:09

6 Answers6

11

I think (guessing) it's because you use type="number". Then digits followed by a dot, e.g. 123., isn't a valid number, and val returns blank.

You could try this instead:

$("[data-input-payment-id]").on("keyup", function(e) {
  var test_value = this.value.replace(/[^\d,]/g, "");
  $(this).val(test_value);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input data-input-payment-id="12">

This uses normal text type and filters out anything but digits in the replace.

Edit:
Changed the regex to match anything but numbers and commas.

SamWhan
  • 8,296
  • 1
  • 18
  • 45
2

This isn't really a solution as I'd personally like to see it, but here is what I did to solve the problem at hand. I changed the JavaScript code to listen for keycode 46 (the .) and I'm returning false on the paste event listener to disable pasting a value into the input.

$("[data-input-payment-id]").on("keypress", function(e) {
  var key = e.charCode ? e.charCode : e.keyCode;
  if (key == 46) {
    return false;
  }
});
$("[data-input-payment-id]").on("paste", function(e) {
  return false;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" data-input-payment-id="12">

It works at least in Chrome and Edge.

Just a student
  • 10,560
  • 2
  • 41
  • 69
Ellisan
  • 563
  • 8
  • 22
  • @Alnitak its not a nice solution, but not every solution is a nice solution. – Ellisan Jul 30 '18 at 10:09
  • 6
    By all means strip the '.' from pasted data, but disabling standard operations is bad, especially for accessibility users. – Alnitak Jul 30 '18 at 10:10
  • 1
    You might also want to listen for - (minus) key and + (plus) key because those are also allowed in the number field and can result in the same issue. Also, note that the keycodes for the Numpad versions of those keys are different. – cnvzmxcvmcx Jul 30 '18 at 10:22
  • Also, `e` can be typed in when the input is of `number` type. – Wiktor Stribiżew Jul 30 '18 at 11:10
  • I have modified your solution to work with paste and without conditionals and also prevent any extra characters such as `e` `+` or `-`. – cnvzmxcvmcx Jul 30 '18 at 11:20
2

I would:

  • Instead of the keyup event, listen to the input event. This way you can also allow pasting.
  • Keep a record of the previous correct value, so that you can roll back to it. This is necessary because type=number inputs will have an empty string as value as soon as the input becomes invalid (as a number). I would store that previous correct value in a data property of the input element
  • With the use of the property validity.stepMismatch you can know whether the current value is violating the step property of the input which by default is 1. With a step of 1, this means entering a number with a decimal separator will be considered a mismatch.
  • As a trailing decimal separator will not (yet) yield a fractional number, it will pass the above validation. So echo the value back into the input when all is OK: this will eliminate any trailing decimal separator that might have been keyed in.

$("[data-input-payment-id]").on("input", function (e) {
    if (!this.validity.stepMismatch) {
        $(this).data("lastValid", $(this).val());
    };
    $(this).val($(this).data("lastValid") || "");  
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number"data-input-payment-id="12">

Having said this, I personally am not in favour of blocking user input in this way: they might for a moment think their keyboard is broke. It is in my opinion better to allow the user to type anything and just indicate with a message next to the input that the input is not valid (until it is).

trincot
  • 317,000
  • 35
  • 244
  • 286
  • Nitpick: this solution does not allow a user to clear the input, because the empty string is not a valid number. You might want to allow that explicitly, or mention it in the answer. – Just a student Jul 30 '18 at 12:07
  • 1
    I further updated this answer after I realised that fractional numbers should not be accepted. – trincot Jul 30 '18 at 15:15
  • I can see why you did this, but I would like to remark (as you already sort of do in your answer) that this does not work at all when the `step` is not 1. For example, with a step of 10 a user will never be able to input a multiple of 10 with a single keystroke. Similar issue occurs with a step of 0.1. Since the question focuses on integers, this should work just fine. – Just a student Jul 31 '18 at 05:55
  • @Justastudent, indeed `step` must be 1, which is the default and is what OP has. – trincot Jul 31 '18 at 13:32
2

Your Keypress example gave me this idea. If you can intercept the keypress event, it is possible to check any validation before adding the actual value. This example also does not require any conditional and is able to filter any non-digit value.

$("[data-input-payment-id]").on("keypress", function(e) {
  if ((this.value + e.key).match(/\D/)) {
    return false;
  }
});
$("[data-input-payment-id]").on("paste", function(e) {
  var pasteData = (e.originalEvent.clipboardData || window.clipboardData).getData('text');
  pasteData = pasteData.replace(/\D/g, '');
  this.value = this.value + pasteData;
  return false;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" data-input-payment-id="12">
  • Allows pasting data with filtering
  • No specific conditionals
  • Can be modified for custom validation

http://jsfiddle.net/xpvt214o/511118/

cnvzmxcvmcx
  • 1,061
  • 2
  • 15
  • 32
1

See MDN docs on inputs of type number:

Value

A Number representing a number, or empty

If the input string cannot be converted to a proper number - such as if the string contains two dots - then accessing the .value property will return the empty string.

The .value (and val() function) will still return strings, but those strings must represent valid numbers (or be the empty string). Rather than setting the element's value unconditionally, simply check to see if the value isn't the empty string first:

$("[data-input-payment-id]").on("keyup", function(e) {
  const val = $(this).val();
  if (val === '') return;
  var test_value = $(this).val().replace(/\./g, "");
  $(this).val(test_value);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" data-input-payment-id="12">

Or you might use a text input, and possibly a pattern:

$("[data-input-payment-id]").on("keyup", function(e) {
  const val = $(this).val();
  var test_value = $(this).val().replace(/\./g, "");
  $(this).val(test_value);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
  <input data-input-payment-id="12">
  <input type="submit">
</form>

<form>
<input pattern="^\d+$" data-input-payment-id="12">
<input type="submit">
</form>
Community
  • 1
  • 1
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 1
    the original issue happens if you type `123..` - so, try that in your code ... once you have the `..` in there you can type 123..1.2.3.4.5.6 if you want :p – Jaromanda X Jul 30 '18 at 10:12
0

$(this).val() is returning an empty string if an input with type="number" has more than one .

You can fix this, by only running the replacing the value if $(this).val() does not return an empty string.

Lars Munkholm
  • 190
  • 1
  • 9