Why is the input type number reset when I have a value starting with "-"?

Asked

Viewed 78 times

-1

I have a input in which I am trying to prevent the user from typing two minor symbols in a row, example:

--155,5

My goal is to clear or remove one of the minor signs and remain the inputado value 155.
However, when trying to capture the value of input in javascript to make any of these negotiations, it is returned empty.

It is possible to print all the entered value --155,5 without altering the type of input for text?

const onChange = (value) => {
    console.log(value)
}
<input onchange="onChange(this.value)" type="number" name="fname"><br><br>
<label for="lname">Valor</label>

2 answers

3


It is possible to print all the entered value --155,5 without altering the type of input for text?

I’m afraid that’s not possible.

According to the WHATWG, in the case of a input type="number", the following rule applies:

If the value of the element is not a Valid floating-point number, then set it to the Empty string Instead.

That is to say: "If the element value is not a valid floating point number, its value is set to the empty string".

And the definition of "Valid floating-point number" is that one:

  1. A character U+002D HYPHEN-MINUS (the "hyphen": -), optional
  2. One of the options below (or both), in this order:
    • One or more digits of 0 to 9
    • The decimal part, consisting of:
      • A single character U+002E FULL STOP (the "point": .)
      • One or more digits of 0 to 9
  3. Optionally followed by:

That is, anything other than that will be considered invalid, and the value of input will be the empty string. That’s why a value starting with two hyphens results in an empty string.


How this is a behavior of browser, is not very good. If you want to get the entered value, you will have to change the type for text and do the validation manually:

function onChange(input) {
    var valor = parseFloat(input.value);
    if (isNaN(valor)) {
        console.log('valor inválido');
        // e aqui você tenta corrigir o valor, se for o caso
    } else {
        console.log('valor válido');
        // usar o valor, etc...
    }
}
<input onchange="onChange(this)" type="text" name="fname">

Already to correct the value, will depend on what you want to do. You want to arrange only the case to start with 2 hyphens? If that’s it, it would be enough - before using parseFloat - do something like:

var valor = input.value;
if (valor.startsWith('--')) {
    valor = valor.slice(1);
}
valor = parseFloat(valor);
...

Of course it’s a naive approach, because if it’s typed -------123, the value will still be invalid. Then you could exchange 2 or more dashes at the beginning for just one:

// troca 2 ou mais hífens no início por apenas um
valor = input.value.replace(/^-{2,}/, '-');

// usar parseFloat, etc...

But still it will only serve for these cases. If any other combination of invalid values is used (such as -1-2.3), it will be very difficult to arrange.

In this case, it is better to simply tell the user that he can only type a certain format, instead of trying to fix all the possibilities of invalid entries. You can use the definition of Valid floating-point number and do something like:

var validNumber = /^-?(\d+(\.\d+)?|\.\d+)([eE][-+]?\d+)?$/;
valor = input.value.replace(',', '.');
if (validNumber.test(valor)) {
    // número válido
    valor = parseFloat(valor);
} else {
    // número inválido, mostra mensagem de erro, etc
}

I only had to exchange the comma for a point (for the decimal point separator), otherwise parseFloat will not work properly (comma may work for type=number in some browsers, according to the locale configured, but the point is guaranteed to always work).

Although in this case the regex is somewhat redundant, since it validates the exact format that parseFloat accepted. Using a regex would make more sense if you wanted to limit values more (for example, not accepting scientific notation, so the last part (of [eE] onward) would be removed from regex, etc).

  • And not directly related, but notice that I switched the Arrow Function by a function "normal" - in this case it does not make so much difference, but there are cases where it does.

0

In this case making a mask, you can prevent typing.

<input onkeyup="onKeyUp(this)" type="tel" name="fname"><br><br>
<label for="lname">Valor</label>

<script>
function onKeyUp(el) {
  var value = el.value || ''
  el.value = value.replace(/^-{2,}/, '-')
  el.value = value.replace(/^(.+)-$/, '$1')
}
</script>
  • 1

    This approach does not work with type="number" that has been asked

Browser other questions tagged

You are not signed in. Login or sign up in order to post.