Scrolling in Select Box fires onchange
In IE when you use the scrollwheel on your mouse it moves the page up and down.. right? wrong. When you are focused on a select box is scrolls through the options - firing off onchange events for every option you view. That can be a problem because you scroll pretty quick, and it will easily tie up the browser if you are using any fun web 2.0 scripts that trigger on a select box's onchange event.
I have an example page of the problem and solution
I have come up with the following behaviour.js workaround. Hopefully you'll find it usefull.
How the Fix Works The problem is when the onchange event runs multiple times in a row without intermediate onclick events. So we just wrap the events of the select element and catch that case.
We wrap the onchange event to set a flag when it runs; and if the flag is already set : unregister itself temporarily. Then we just clear the flag onclick and onblur. We also re-set the onchange function onblur (if necesary).
Lastly this script does a dom check so the fix is only applied in IE.
function switchfunctions(el){
el._scrolling = el.onchange;
el.onchange = null;
}
var scrollfix = {
'select' : function (el){
if ( typeof(document.media)=='string'){// dom check for IE
// grab the real functions
el.scrollonchange = el.onchange ? el.onchange : function(){return true;};
el.scrollonclick = el.onclick ? el.onclick : function(){return true;};
el.scrollonblur = el.onblur ? el.onblur : function(){return true;};
el.scrollonfocus = el.onfocus ? el.onfocus : function(){return true;};
// make a new onchange which will switch if it's fired twice in a row before onclick or onblur
el.onchange = function(){
debug("new onchange");
if (this.scrolling && this.scrollingfix){switchfunctions(this);return false;}
if (this.scrollingfix){this.scrolling=true;}
el.scrollonchange();
}
// now set the flag so we know this happened between onchange()'s
el.onfocus = function(){
this.scrolling = false; // set flag
this.scrollingfix = true;
this.scrollonfocus();
}
// now set the flag so we know this happened between onchange()'s
el.onclick = function(){
this.scrolling = false; // set flag
this.scrollingfix = true;
this.scrollonclick();
}
// set flag so we know this happened between scrolling && re-set the onchange if needed
el.onblur = function(){
if (this._scrolling){
this.scrolling = false; // set flag so orignal onchange is happy
this.onchange = this._scrolling; // unswitch functions
this.onchange();
this._scrolling = false;
}
this.scrolling = false; // set flag
this.scrollingfix = false;
this.scrollonblur(); // run original funciton
}
}
}
};
Behaviour.register(scrollfix);
Adding small behaviour scripts is a useful approach for "fixing" browsers. It's something I also used when working around the autocomplete not firing onchange problem I identified last week.
Thanks M$ for wasting another day of my life.
Update 10/24 Updated to add a wrapper around onfocus().
4 years, 5 months ago
Hi,
Thanks for this helfpul script. One odd thing I discovered in doing all this was that with an id on my submit button, my Javascript onchange call (to “this.form.submit()”) didn’t work for my multiple length select box (though it was ok with single length select boxes I had).
4 years, 4 months ago
Hi,
The example of your solutions seems to work fine.
But I noticed when you use the up- and down-keys to scroll through the options in the select box after an initial choise the subsequent choises are do not fire the modified onChange event
So choosing say option 2bbb after scrolling up and down fires the onChange event correctly the first time. Then without leaving the selectbox scroll up and down again and choose, let us say, option 3bbb does not fire the onChange.
I would have expected that the event would fire again.
Cheers!
4 years, 4 months ago
@Zon: that is the fix, there should NOT be any onchange events fired untill you leave the the field. This includes keyboard navigation.
Try it out on a text field. Onchange fires after you leave the field, not before.
Having the onchange fire every time you scroll through an option is the bug.
4 years, 4 months ago
I understand the bug: the onChange fires during scrolling; that is too many times.
What I want to make clear that onChange should fire each time a option is selected (and not during scrolling through the options).
Thus :
A) Entering the selectbox does not fire the onChange event.
B) Then scrolling through the options does not fire the event.
C) Selecting an option [enter or click] DOES fire the event, the first time
D) Without leaving the select box scroll through the options again; OnChange should not be fired
E) Select an other option [click or enter-key] the OnChange should be fired (= the second time it is fired).
The sequence I described is the behaviour I would expect and is the actual standard behaviour in Firefox.
In your fix for IE everything works as expected and as in Firefox up to point E. In your fix the onChange does not fire for the second time if you do not leave the selectbox.
I hope it is clear what I am trying to say.
Anayway your fix helps me a lot because the way I need to use it makes sure that the user leaves the field after an option is selected.
Cheers!
4 years, 3 months ago
I am not able to do a simple thing because of tag libraries. I want to add onChange listner to select drop down box through javascription after building the page.
4 years ago
Jehiah,
Have you seen instances in Firefox where opening a select box, scrolling over the options and then blurring it (without selecting anything) triggers an onChange for the last item you were mouseover’d? I am getting this behavior in a small app I am building with Dojo. Firefox works like normal on non-dojo’d pages but connecting events to the onfocus, onchange and onblur events have somehow caused it to fire onchange even when there is no onclick. Any ideas? Is this related?
3 years, 4 months ago
My solution to this problem had to account for clicks as well as scrolling, as onChange in a selectbox also fires whenever the box is clicked (I have a multiple select).
If you’re running into that, then the easiest way is to loop through and check for changes. In my case, I was sorting the list on change (when options are added/removed), so I built a new options array locally, then compared each value in a for loop. If everything has the same value at the same index, then there was no change, so just return false.
It might seem inefficient, but it’s not too bad with small lists. Obviously a different situation too, but it could be useful to someone.