128

How can i get the "real" value of an <input type="number"> field?


I have an input box, and i'm using newer HTML5 input type number:

<input id="edQuantity" type="number">

This is mostly supported in Chrome 29:

enter image description here

What i now need is the ability to read the "raw" value the user has entered in the input box. If the user has entered a number:

enter image description here

then edQuantity.value = 4, and all is well.

But if the user enters invalid text, i want to color the input-box red:

enter image description here

Unfortunately, for a type="number" input box, if the value in the text-box is not a number then value returns an empty string:

edQuantity.value = "" (String);

(in Chrome 29 at least)

How can i get the "raw" value of an <input type="number"> control?

i tried looking through Chrome's list of other properties of the input box:

enter image description here

i didn't see anything that resembles the actual input.

Nor could i find a way to tell if the box "is empty", or not. Maybe i could have inferred:

value          isEmpty        Conclusion
=============  =============  ================
"4"            false          valid number
""             true           empty box; not a problem
""             false          invalid text; color it red

Note: You can ignore everything after the horizontal rule; it's just filler to justify the question. Also: don't confuse the example with the question. People might want the answer to this question for reasons other than coloring the box red (One example: converting the text "four" into the latin "4" symbol during the onBlur event)

How can i get the "raw" value of an <input type="number"> control?

Bonus Reading

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • 2
    The 'real' value of a numeric input field has to be a number. If you want to allow input other than numeric values, then `number` is not the input type you are looking for; use a normal `text` input. – robertc Sep 17 '13 at 14:29
  • 7
    @robertc Chrome is the agent allowing input other than numbers; i just need to know that they've *entered* things other than numbers. – Ian Boyd Sep 17 '13 at 14:30
  • 1
    Check the field's [`validity` state](http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#dom-cva-validity) - I would expect `typeMismatch` but I haven't checked myself. – robertc Sep 17 '13 at 14:36
  • You cannot do this. Either use an `input type="text"` field, or accept that any non-numeric value will be ignored. – user229044 Sep 17 '13 at 15:14
  • What if you write a little JS function which sets `type` to `text`, reads the `value` and sets `type` back to `number`? – Reeno Sep 17 '13 at 15:16
  • 1
    @Reeno Changing the `type` will clear the field. – user229044 Sep 17 '13 at 15:18
  • @robertc: Good idea, but it does not work. It just acts like an empty input that validates. – Bergi Sep 17 '13 at 15:27
  • Why do you want to know the raw value? – int32_t Sep 18 '13 at 23:08
  • 2
    @int32_t Read the sixth line down (i.e. *"But if the user enters..."*) – Ian Boyd Sep 18 '13 at 23:19
  • I find the way this was designed annoying...although I can get the `validity` state, it's not really convenient for being able to store a single-source-of-truth text value in my React model. And I want to use `` so that it will default to a numeric keyboard in tablets and smartphones. – Andy Jun 01 '15 at 18:10
  • 6
    My use case... I have two numeric fields: latitude and longitude. I'd like to detect if someone pastes in "lat, lon" and handle appropriately. This is currently impossible with type="number". since "lat, lon" is invalid.. there's no way to get the "raw" value to perform a regex on. Another use case: displaying a customer error : "`blah` is an invalid number". – Brad Kent Apr 19 '16 at 03:18

4 Answers4

61

According to the WHATWG, you shouldn't be able to get the value unless it's valid numeric input. The input number field's sanitization algorithm says the browser is supposed to set the value to an empty string if the input isn't a valid floating point number.

The value sanitization algorithm is as follows: If the value of the element is not a valid floating-point number, then set it to the empty string instead.

By specifying the type (<input type="number">) you're asking the browser to do some work for you. If, on the other hand, you'd like to be able to capture the non-numeric input and do something with it, you'd have to rely on the old tried and true text input field and parse the content yourself.

The W3 also has the same specs and adds:

User agents must not allow the user to set the value to a non-empty string that is not a valid floating-point number.

j08691
  • 204,283
  • 31
  • 260
  • 272
  • 6
    It would be useful if user agents did not allow the user to set the value to a non-empty string that is not a valid floating-point number. But if whatwg says it cannot be done; then that's the answer. Workaround for my current need added below. – Ian Boyd Sep 17 '13 at 15:45
  • 64
    *By specifying the type (``) you're asking the browser to do some work for you.* Personally, I was just asking mobile browsers to show a numeric keypad, and got the validation as an unpleasant extra. Most of these problems stem from the fact that the `type` attribute determines both validation rules and rules about what input mechanism to display, but it's quite possible to want to show a numeric keyboard to mobile users without also wanting number validation applied to desktop users. HTML 5.1 will at least solve this problem eventually with the `inputmode` attribute. – Mark Amery Apr 19 '14 at 22:54
  • 4
    but when the browser does not do enough, I would like to be able to complete it. such as removing spaces in the input, inferring the decimal point... – njzk2 May 28 '14 at 14:20
  • 1
    also, in various languages, such as french, there are 2 words for number. one for numbers as identifiers, such as credit card numbers, and one for counting numbers, such as floating point numbers. – njzk2 May 28 '14 at 14:43
  • You can use type="tel" to achieve numeric pad in mobile. – Moti Korets May 07 '15 at 21:45
  • 1
    @MotiKorets doesn't work for entering floating point numbers as iPhones don't put a decimal point on the keyboard. Unfortunately devs are pretty screwed at the moment as far as providing a nice floating point entry UX... – Andy Dec 17 '15 at 16:27
  • Asking the browser to do work for you is great... but then how the @#*&^$#@$ do I get it to display a certain input method in mobile and NOT do the work for me (instead of breaking)? – Goblinlord Jan 11 '17 at 04:25
54

It doesn't answer the question, but the useful workaround is to check

edQuantity.validity.valid

The ValidityState of an object gives clues about what the user entered. Consider a type="number" input with a min and max set

<input type="number" min="1" max="10">

We always want to use .validity.valid.

Other properties only give bonus information:

┌──────────────┬────────┬────────╥───────────┬─────────────────┬────────────────┐
│ User's Input │ .value │ .valid ║ .badInput │ .rangeUnderflow │ .rangeOverflow │
├──────────────┼────────┼────────╫───────────┼─────────────────┼────────────────┤
│ ""           │ ""     │ true   ║ false     │ false           │ false          │ valid because field not marked required
│ "1"          │ "1"    │ true   ║ false     │ false           │ false          │ 
│ "10"         │ "10"   │ true   ║ false     │ false           │ false          │
│ "0"          │ "0"    │ false  ║ false     │ true            │ false          │ invalid because below min
│ "11"         │ "11"   │ false  ║ false     │ false           │ true           │ invalid because above max
│ "q"          │ ""     │ false  ║ true      │ false           │ false          │ invalid because not number
│ "³"          │ ""     │ false  ║ true      │ false           │ false          │ superscript digit 3
│ "٣"          │ ""     │ false  ║ true      │ false           │ false          │ arabic digit 3
│ "₃"          │ ""     │ false  ║ true      │ false           │ false          │ subscript digit 3
└──────────────┴────────┴────────╨───────────┴─────────────────┴────────────────┘

You'll have to ensure that the the browser supports HTML5 validation before using it:

function ValidateElementAsNumber(element)
{
   //Public Domain: no attribution required.
   if ((element.validity) && (!element.validity.valid))
   {
      //if html5 validation says it's bad: it's bad
      return false;
   }
   
   //Fallback to browsers that don't yet support html5 input validation
   //Or we maybe want to perform additional validations
   var value = StrToInt(element.value);
   if (value != null)
      return true;
   else
      return false;
}

Bonus

Spudly has a useful answer that he deleted:

Just use the CSS :invalid selector for this.

input[type=number]:invalid {
    background-color: #FFCCCC;
}

This will trigger your element to turn red whenever a non-numeric valid is entered.

Browser support for <input type='number'> is about the same as :invalid, so no problem there.

Read more about :invalid here.

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • Doesn't work in Opera. [It says *valid*](http://jsfiddle.net/FBs4J/2/) even if you input a string. – Bergi Sep 17 '13 at 15:32
  • Opera supports the `.validity` property, but doesn't correctly handle `.valid`?! – Ian Boyd Sep 17 '13 at 15:35
  • It does, but when is a number input [invalid](http://dev.w3.org/html5/spec-preview/constraints.html#constraints)? It just acts as if the input was empty. A `typeMismatch` might make sense, but that is only for email or url types… – Bergi Sep 17 '13 at 15:44
  • @Bergi The table above gives examples where number inputs can be invalid: "q", "11" (then the max is 10), "0" (when the min is 1), "" (then the element is `required`) – Ian Boyd Sep 17 '13 at 15:48
  • Opera does not have that `badInput` property on Validity objects, which seems to be the reason for the different behavior. Is that property standardized anywhere? – Bergi Sep 17 '13 at 17:26
  • 1
    @Bergi [`.badInput` was added 11/20/2012](http://www.whatwg.org/specs/web-apps/current-work/multipage/association-of-controls-and-forms.html#dom-validitystate-badinput). But nobody should be looking at `badInput` to see if input is valid; they should be looking at `.valid`. It is possible (and correct) for `.badInput` to be false, and still have invalid input. `.valid` is defined as the absence of any validation errors (E.g. mismatches, overflows, underflows), of which `.badInput` is only one kind of error. Note the chart above where `.badInput` is false, but the input is still invalid. – Ian Boyd Sep 17 '13 at 17:38
  • Rather than using a fictitious `StrToInt` method that is left for the reader to implement, wouldn't doing `return !isNan(element.value)` be adequate? – Mark Amery Feb 17 '14 at 10:32
  • @MarkAmery I'm not sure. Would `!isNan("two")` recognize a *"good"* value? – Ian Boyd Feb 18 '14 at 03:11
  • The trickiest thing about getting into html5 validation is that the validity object is the source of truth - if you do and type "foo" in the field, and then do input.value, there IS NO VALUE as you would expect. It only has a value, when input.validity.valid = true. – httpete Mar 20 '15 at 16:23
11
input.focus();
document.execCommand("SelectAll");
var displayValue = window.getSelection().toString();
int32_t
  • 5,774
  • 1
  • 22
  • 20
  • Everywhere: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand – fregante Aug 14 '15 at 23:00
  • Doesn't work in firefox : https://bugzilla.mozilla.org/show_bug.cgi?id=85686 (note that this bug was filed in 2001 !!) – Brad Kent Apr 19 '16 at 02:53
  • Firefox, as always, is correct. This should not work and is a [bug](https://bugs.chromium.org/p/chromium/issues/detail?id=558919) – vsync May 17 '18 at 12:16
4

Track all pressed keys based on their key codes

I suppose one could listen to the keyup events and keep an array of all characters entered, based on their keycodes. But it's a pretty tedious task and probably prone to bugs.

http://unixpapa.com/js/key.html

Select the input and get the selection as a string

document.querySelector('input').addEventListener('input', onInput);

function onInput(){
  this.select(); 
  console.log( window.getSelection().toString() )
}
<input type='number'>

All credit to: int32_t

vsync
  • 118,978
  • 58
  • 307
  • 400
sandstrom
  • 14,554
  • 7
  • 65
  • 62
  • [That solution was tried elsewhere, and doesn't work](http://stackoverflow.com/questions/11365686/how-to-get-text-of-an-input-text-box-during-onkeypress). Especially when the users presses `Delete`, `Backspace`, `Ctrl+X`, `Ctrl+V`, `Right-click-cut`, `Right-click-paste`. – Ian Boyd Oct 31 '13 at 12:30
  • I agree with you, basically what the OP asked isn't possible. However, both hacks I mentioned (and they are hacks, I don't deny that) do work to some extent. Perhaps they can be useful to someone, in some case? – sandstrom Oct 31 '13 at 13:11
  • amazingly, the selection thing seems to work. What are the limitation of that method? – njzk2 May 28 '14 at 15:24
  • Limitations: the text is visually selected. If the user types something the content will be gone – fregante Aug 14 '15 at 23:01
  • Edited with a live demo which shows how bad this method is – vsync May 17 '18 at 12:20