Thursday, June 22nd, 2006
Autcompletion Issues with Yahoo, Scriptaculous Libraries
Cheng Guangnan reports on a potential issue with the autocompletion/suggestion support offered by both Yahoo UI and Scriptaculous libraries. The problem involves parallel calls - there’s the potential for an initial list of suggestions to be displayed after a subequent list. His screencasts show what’s going on.
1. “2006†is typed.
2. A request of “2006†sent to the server.
3. User continues typing and now “200607†typed.
4. Another request of “200607†sent to the server.
5. User waiting for feedback.
6. The second request return, it show the popup.
7. The first request return, it show the popup with data returned for “2006â€.
If that’s the case (and we haven’t verified it!), the problem could be solved by some form of Call Tracking. If the first call comes back after the second, simply discard it.













Kind of reminds me of Apple’s annoying Spotlight search feature which is nearly useless on anything but the fastest machines. I am not sure exactly how these libraries are working but I think that coding in a delay of two to three seconds after the users last keypress would be a good way to deal with this that would also help reduce the load on the server.
Twist, you can see an example of that (adding a delay) at http://www.ajaxify.com/tutorial/. The “Streamlining Performance” step reduces a similar kind of error, in which results get merged from two different queries. A delay can be useful, but still not all that robust - the first call still might get stuck somewhere and take a few more seconds to process.
How about a patch…? :)
I think a callstack like this is implemented in, for example, HTML_AJAX - a PHP package found in PEAR.
typo.. “after the second” ?
See my demo at http://munich.schwarz-interactive.de/autocomplete.aspx, do you get the same problem there? I couln’t get a “wrong” result.
It should be noted that he is selling a solution for $50 to the ‘problem’ in these libraries.
Autcompletion Issues with Yahoo, Scriptaculous Libraries
Cheng Guangnan reports on a potential issue with the autocompletion/suggestion support offered by both…
This seems like an easy problem to fix if it does exist. With every request send an incrementing number. Have the response send back that number. If your receive a number that is less than a number you have previously received just discard the request. Networking protocols have been doing this for ages.
Yes, this would be an idea. I’m currently not allowing to start another request while one is running.
Wasn’t there a talk about this at this year’s PHP conference in London?
It’s hardly a revelation…
And the preview thing on these comments (I assume…) means letters don’t appear for a good 5 seconds after I’ve typed them…rather annoying.
Is it ever useful to have a list of search results for a string that isn’t the value of the input field any more? I haven’t ever used Autocomplete, so I don’t know. But if it isn’t, then surely the callback handling the Ajax request could just check to see if the text in the input field is the same as the string that was sent to the server?
In which case step 7 would become: the first request returns, but does nothing because the text in the input field is no longer “2006″.
How about calling abort() on the XMLHttpRequest object before sending the second request?
Why call again to the server?
If the last query is the beginning of the new search query, so we can just filter the last search result and show the filtered list.
Else, call again to the server.
Eric, indeed that’s what I was getting at with Call Tracking. Also, you don’t actually have to transfer the number back and forth if you don’t want (ie you can leave the server-side alone); just associate an incrementing call ID with the XHR itself. When the response comes back, the handling XHR looks at its own call ID and decides whether it’s the newest XHR to be used so far.
I encourage you guys to check this one out too:
http://developer.ebusiness-apps.com/technologies/webdevelopment/codeandcomponents/ebawebcombov3/media/demos.htm
@Thomas: I agree with you in spirit, but I’m pretty sure this guy is just out to hawk his wares. He’s been spamming all Ajax and web-dev related mailing lists lately. It actually looks like he ran yours on a slower machine to make his product look better.
Nate, you can’t say I’m not correct because of I do spam.
Sorry for spam you. :P
I record the screencast on my AMD Althon 2000+ with 1G memory. I made it *played slowly than the actuly speed* to make sure that everyone could see what happen clearly.
Did someone test the suff from Michael? Where can I get this control? (Sorry, I’m .NET developer).
An easy fix for the Yahoo libraries is to modify _populateList. If the query does not currently match whatever is in the text box, just ignore it. It works quite well for me.
if (sQuery != oSelf._oTextbox.value) { return; }
I found a workaround to this for Scriptaculous using the onLoading option.
// global var
var my_search;
// option for Ajax.Autocompleter
onLoading: function(request)
{
// kill the last search that might be pending
try { my_search.abort(); } catch (e) {}
my_search = request;
}
This problem does exist, and once you see it, it takes 10 minutes to fix, if that. I don’t know if it warrants this much attention though.
I’ve been working this problem for a while. This is also a problem when you use Prototype to build and track your ajax request/responses. You will need to build some sort of call stack mechanism and return a parameter with your response that helps you match it up with the request.
Ugh…
Isn’t this simply one of the issues with using async requests? Your responses may come back in a different order than the requests were went. Using a sequence sent with each request and returned by a response will help, but only if the UI state of the suggestion box is orthogonal to any other page state.
Its not that hard to slove, my guess would be just to Abort the Ajax call, when trying to send a new Ajax call on key up.
1. User enters 2006
2. (on key up) Ajax Call, find match for 2006 results query
3. user types 200698 or whaterver.
4. abort #2 query, ajax call
5. Ajac call for #3
6. Loop if needed.
All the librarys do support some method of abort() for ajax requests,
right? or no?
The simplest way is to only allow 1 request pending at anytime. If a higher priority request is required, pending requests can be aborted.
I have a similar problem on my real estate search engine. I’ve tried aborting XML HTTP request before sending new one, and the problem does indeed get fixed, however another one is introduced: fast typing does not produce any results at all…behavior seems very strange. PS I’ve tried all possible time intervals
For script.aculo.us just use Form.Element.DelayedObserver in Autocompleter (controls.js):
Wrong way (as you can see in controls.js):
Event.observe(this.element, “blur”, this.onBlur.bindAsEventListener(this));
Event.observe(this.element, “keypress”, this.onKeyPress.bindAsEventListener(this));
Right way:
Event.observe(this.element, “blur”, this.onBlur.bindAsEventListener(this));
new Form.Element.DelayedObserver(this.element, 0.5, this.onKeyPress.bindAsEventListener(this));
In prototype 1.5.0_rc1 and scriptaculous 1.6.4 we had this problem and in 9.5 minutes we had a solution.
To the definition of Ajax.Request in prototype.js we added the function:
abort: function() {
this.transport.abort();
}
In Scriptaculous (controls.js) Ajax.Autocompleter:
we declared a global variable:
var my_search;
we updated getUpdatedChoices() so the last two lines in the method look like:
//line added
try {my_search.abort();} catch (e) {}
//line changed
my_search = new Ajax.Request(this.url, this.options);
Thanks to zac for leading us down the right path.