web analytics

Disabling MouseWheel Scroll Event on jQuery UI’s spinner control

We recently found an interesting quirk in the Composable DataFlow designer. Spin Module inputs seemed to randomly change values. While editing a DataFlow, sometimes a number would flip from 0 to 1, or 0 to  -1, or 1 to 2. The root cause was pretty interesting, and, and the solution ended up being relatively simple.

Module with two spinner inputs.

Currently, the canvas component is listening for mousewheel events, and then panning the canvas appropriately. Mousewheel events can originate from any child elements based on cursor location, including UI spinners. It just so happens that JQuery UI’s spinner is also listening for mousewheel events. Even if the spinner element is not in focus or selected, and the mouse cursor is over the element, the spin element will detect the mousewheel event and change its value.

So while panning with the mouse, if your cursor just so happened to be over a spin element,  and you moved the mousewheel, it would change its value. Yikes!

Very old versions of jQuery’s (circa 1.3) spinner actually had an option called ‘mouseWheel’ and it could be set to false. In the latest versions, this is no longer there and now you end up needing to cancel the event. There are a few options to do this. One would be to bind to the mousewheel event on the element, and then call evt.stopImmediatePropagation(), which would prevent the spinner from getting the event, but also anyone up the chain too. A call to preventDefault() or stopPropogation() would not work either since there was no default listener present, and the spinner listener was not a parent, but on the same element.

Instead, we bind to the spinners spin event. If this originated from a mousewheel, then we prevent the default spinners behavior from happening. This cancels the spin event, but still allows the original mousewheel event to bubble up, allowing the canvas to scroll even if the cursor is over a spin element. Listening to the ‘spinstart’ event, and calling preventDefault() will not work, as it is too early in the lifecycle of the event, and prevents the bubbling up of the mousewheel event.