When you use overflow:auto in your css in conjunction with Scriptaculous’ Autocomplete, there is a bug that makes the entire page jump around when you use the arrow keys on your keyboard to navigate up and down through the suggestion list. This bug normally appears only when the page itself is long enough to require a scroll bar.
I managed to come up with a very clean working solution by hacking the controls.js file that comes with scriptaculous. The solutions requires replacing the markPrevious and markNext functions and adding a small line of code to the updateChoices function.
Currently, markPrevious and markNext are telling the page to jump around like that, and I’m not sure why! As far as I can tell (please let me know otherwise) this solution could be included in the scriptaculous without breaking a thing (hint, hint to the scriptaculous team).
To implement the solution, replace:
markPrevious: function() { if(this.index > 0) this.index--; else this.index = this.entryCount-1; this.getEntry(this.index).scrollIntoView(true); }, markNext: function() { if(this.index < this.entryCount-1) this.index++; else this.index = 0; this.getEntry(this.index).scrollIntoView(false); }, |
With:
markPrevious: function() { if(this.index > 0) {this.index--;} else { this.index = this.entryCount-1; this.update.scrollTop = this.update.scrollHeight; } selection = this.getEntry(this.index); selection_top = selection.offsetTop; if(selection_top < this.update.scrollTop){ this.update.scrollTop = this.update.scrollTop-selection.offsetHeight; } }, markNext: function() { if(this.index < this.entryCount-1) {this.index++;} else { this.index = 0; this.update.scrollTop = 0; } selection = this.getEntry(this.index); selection_bottom = selection.offsetTop+selection.offsetHeight; if(selection_bottom > this.update.scrollTop+this.update.offsetHeight){ this.update.scrollTop = this.update.scrollTop+selection.offsetHeight; } }, |
Now find the updateChoices function and just after the code this.stopIndicator(); add this.update.scrollTop = 0; so that it looks like this:
this.stopIndicator(); this.update.scrollTop = 0; this.index = 0; |
I’ve tested in FF 2.0.0.4, FF 3.0.5, Chrome 1.0.154.43, Safari 3.2.1, Opera 9.5.1, IE 7.0.5730.13 and IE 6.0.2600 without problems.



Subscribe to
Very nice Jason, GOOD WORK
You are a f*?&king Genius. I fought against this issue for days until I found this hack. I’m sorry for the “f*?&king” but I’m so happy to have found this.
Thank you so much !!!!!
I stumbled upon this very annoying problem this morning and after some googling I found your solution, which works as advertised.
Good work! The only modification I did is that instead of hacking the original files I extended the Autocompleter class and put in some local caching as well.
[code]
Ajax.CachedAutocompleter = Class.create();
Object.extend(Object.extend(Ajax.CachedAutocompleter.prototype, Autocompleter.Base.prototype), {
initialize: function(element, update, url, options) {
this.baseInitialize(element, update, options);
this.options.asynchronous = true;
this.options.onComplete = this.onComplete.bind(this);
this.options.defaultParams = this.options.parameters || null;
this.url = url;
this.cache = {};
},
getUpdatedChoices: function() {
var t = this.getToken();
if (this.cache[t]) {
this.updateChoices(this.cache[t]);
} else {
entry = encodeURIComponent(this.options.paramName) + '=' +
encodeURIComponent(t);
this.options.parameters = this.options.callback ?
this.options.callback(this.element, entry) : entry;
if(this.options.defaultParams)
this.options.parameters += '&' + this.options.defaultParams;
new Ajax.Request(this.url, this.options);
}
},
onComplete: function(request) {
this.updateChoices(this.cache[this.getToken()] = request.responseText);
},
// Page jump fix
markPrevious: function() {
if (this.index > 0) {
this.index--;
} else {
this.index = this.entryCount-1;
this.update.scrollTop = this.update.scrollHeight;
}
selection = this.getEntry(this.index);
selection_top = selection.offsetTop;
if (selection_top < this.update.scrollTop) {
this.update.scrollTop = this.update.scrollTop - selection.offsetHeight;
}
},
markNext: function() {
if (this.index this.update.scrollTop + this.update.offsetHeight) {
this.update.scrollTop = this.update.scrollTop+selection.offsetHeight;
}
},
updateChoices: function(choices) {
if (!this.changed && this.hasFocus) {
this.update.innerHTML = choices;
Element.cleanWhitespace(this.update);
Element.cleanWhitespace(this.update.down());
if (this.update.firstChild && this.update.down().childNodes) {
this.entryCount =
this.update.down().childNodes.length;
for (var i = 0; i < this.entryCount; i++) {
var entry = this.getEntry(i);
entry.autocompleteIndex = i;
this.addObservers(entry);
}
} else {
this.entryCount = 0;
}
this.stopIndicator();
this.update.scrollTop = 0;
this.index = 0;
if (this.entryCount==1 && this.options.autoSelect) {
this.selectEntry();
this.hide();
} else {
this.render();
}
}
}
});
[/code]
thanks, your solution works great!
Awesome, i find this solution for a week, thx for ur help !! just wonder is that Scriptaculous team don’t know this bug or they ignore this bug …
Thanks a lot buddy!!
Great fix
Love you man… Although I don’t have overflow:auto in my css, this bug was my nightmare. Never more… Thx much.
Thanks alot for your your Solutions. It works extremely well. Also, Thanks for Janos Novak for making a new class!
This is just plain beautiful … a million thank. There is another modification to autocompleter which enables/disables autcompleter at http://dev.rubyonrails.org/ticket/7210.
again thanks to Jason Gill
Thank you so much, This solved my issue.
Thanks a lot, your solution was very helpfull!
thanks, that was very helpful.
You rock! This saved me a ton of time – thanks dude!
thanks!
Hi
When i click on scrollbars of autocomplete DIV, it get hidden automatically in IE 7.0.
Please help .
Regards
Dharm
@Dharm I just posted a link to a solution to that same problem in my comments on this post: http://blog.gilluminate.com/2005/05/24/scrolling-in-internet-explorer-causes-elements-to-lose-focus/comment-page-1/#comment-5836
Love you man… Although I don’t have overflow:auto in my css, this bug was my nightmare. Never more… Thx much.
Thanks for posting the info. This is helpful. But my problem is that in the suggest list, when using the arrows up/down in firefox – the selection skips the next entry. Example if i use arrow key to go down from 1st entry, instead of going to 2nd it directly goes to 3rd. I did try your code, but it doesn’t seem to help in this situation. Any pointes would be greatly appreciated! Thanks in advance…
Oh and by the way the issue I mentioned is only on Firefox and Chrome and IE works fine.
Many, many thanks! Saved me a major headache.
Excellent Jason, nice deed
Thank you so much for finding a fix.
If you ever come through Barcelona, drop me a line. I owe you a beer
Its not working me.
(I tried on test server)
You can see the problem here: http://www.bud.hu/english ticket booking
Thank you so much!!!
Thank you, thank you, THANK you!
It is SUCH a relief not to have that damn jumpy behavior!
Have you heard anything from the Scriptaculous folks about whether they will implement your fix in a future release?
Cheers
–Dan
I have not. Though I haven’t contacted them directly yet.
Thanks. I would join in the encouragement that you submit this as a patch to scriptaculous itself.
I did submit it on their forums. I just don’t know how to go about submitting as a patch.