Ellisan
Ellisan

Reputation: 573

Replacing a dot using JavaScript instead removes everything

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?

Upvotes: 16

Views: 2671

Answers (6)

Ellisan
Ellisan

Reputation: 573

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.

Upvotes: 2

trincot
trincot

Reputation: 350137

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).

Upvotes: 2

SamWhan
SamWhan

Reputation: 8332

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.

Upvotes: 11

cnvzmxcvmcx
cnvzmxcvmcx

Reputation: 1111

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/

Upvotes: 2

CertainPerformance
CertainPerformance

Reputation: 370679

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>

Upvotes: 1

Lars Munkholm
Lars Munkholm

Reputation: 308

$(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.

Upvotes: 0

Related Questions