'HTML input type number JavaScript onchange fires twice?

I can't believe I couldn't find any discussion on this already... There have been questions of how to handle events from the HTML5 form element <input type="number"/>... There seems to be a good bit of browser inconsistency so far. But has no one else noticed this?

The onchange event happens twice for me when using an arrow key to go from blank to a number. Try for yourself. Seems to be changing to 0 instantaneously and then 1. I'm using Chrome 23.0.1271.64 m. Haven't tried other browsers.

Is it a bug? Expected? Similar across browsers? A better question is, what's the best way to avoid this behavior? I have some instant-validation stuff going on, and with 0 being invalid, my friendly "You can't do that" text appears for a flash before going away again. In the question linked above it was suggested to use the oninput event but there was some disagreement on how it worked across browsers.

I guess the best way would be forget the number type altogether, as it isn't fully supported itself yet. I'm interested to see if others are getting this though, and how they're dealing with it.



Solution 1:[1]

I reproduced it.

If the input starts out blank. on first press of the up or down buttons it sets it to 0 and then sets it to either 1 or -1.

This is not a bug.

It is a convenience for you! It did not have to start at 0, it could have started at 100000000000000000, but it didn't :-)


If the input does not start as blank, then you have no issue whatsoever.

Solution 2:[2]

This is indeed a good point.

But first: A way to avoid this

Set a focus handler onfocus save the value. Set a blur handler onblur compare current value with saved value, if value has changed trigger/dispatch/fire a 'comittedchange' event. -> Use commitedchange event instead of busted change event :-)

Here are some thoughts. But first read the HTML5 specification for the change event.

Now some history

The HTML4 specification had a different definition (if a value/checkednes changed and the elements is activated or unfocused the event occurs), which was a bad thing especially for checkboxes and radiobuttons (This is the reason why people are using the click and not the change event for those elements (or jQuery)).

The new HTML5 spec

The new spec combines the first definition and adds some extra called 'explicit commit action'. Actually I do not really understand what this means, but I'm sure, while a user presses the mouse on a spinbutton (type=number), this user hasn't done a commit action, he is still interacting with the form and still might do a input/change.

Additionally HTML5 added the input event, to inform the developer "sooner" about some non final changes. For example to combine this with the datalist element and allow dynamic changes i.e. create a autosuggest.

The reality: browsers

In case of input types with spinbuttons (type number, time etc.). Opera and Chrome behave very similiar (interacting with spinbutton triggers input and change) and Safari trigger the change onblur. In case of a type=range all browsers are handling this equal. The change event and the input event is triggered all the time, while dragging the mouse. Fine, we have two different events with different specification and usecases, but they are doing the same thing in reality (Yeah).

The reality: developers

Well there are a lot of tutorials and scripts out there using the change event for type=range for use cases, which should take the input event instead, but as you know, developers are stupid and only read 1% of the specification.

End of story

The old definition was bad and made it useless. The new specification was improved, but isn't understandable, was mis-used and bad implemented... And now??? I think noone wants to break old bad HTML5 tutorial / script code.

If you want this to change be my hero.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Naftali
Solution 2