Reputation: 33071
I'm looking at the jQuery UI autocomplete documentation and looking at their example of a callback with caching:
$(function() {
var cache = {}, lastXhr;
$('#Field').autocomplete({
minLength: 2,
delay: 600,
source: function(request, response) {
var term = request.term;
if( term in cache ) {
response(cache[term]);
return;
}
lastXhr = $.post('LoadData', function(data, status, xhr) {
cache[term] = data;
if(xhr === lastXhr) {
response(data);
}
});
}
});
});
The code wires up a field to use autocomplete and stores a cache of queries that have been hit already. The following line is used so if one query takes longer than another it doesn't replace the autocomplete values:
if(xhr === lastXhr) {
response(data);
}
If I start typing a few letters and it goes to the server to query the data, then I pause and start typing again, it will trigger another trip to the server. If the first query finishes AFTER the second one then the loading icon never goes away. I assume this is because it is never calling the response()
callback. Is there a way that I can cancel the first request once a second request is made?
Upvotes: 4
Views: 2510
Reputation: 1
You can ensure that autocomplete only processes the last response by including the search string in the response, and telling autocomplete the name of the json response property that holds the search string with the matchResponseProperty. See http://easyautocomplete.com/guide#sec-async
Upvotes: 0
Reputation: 1113
I would just make :
if(xhr === lastXhr) {
response(data);
} else {
return false;
}
Upvotes: 0
Reputation: 854
Cache your final result along with the request. You can then make sure that the response callback is called every time and the lastData will ensure that the correct data is used, regardless of whether the queries come back out of sync.
As in:
$(function() {
var cache = {}, lastXhr,lastData;
$('#Field').autocomplete({
minLength: 2,
delay: 600,
source: function(request, response) {
var term = request.term;
if( term in cache ) {
response(cache[term]);
return;
}
lastXhr = $.post('LoadData', function(data, status, xhr) {
cache[term] = data;
if(xhr === lastXhr) {
response(data);
// Store the latest data
lastData = data;
}
else
{
// Queries have come back out of sync - this isn't the last one
// but we need to call response to stop the spinner
response(lastData);
}
});
}
});
});
Upvotes: 1
Reputation: 30099
Could you just add lastXhr.abort()
right before you do the post? This would cancel a previous request each time you start a new one.
$(function() {
var cache = {}, lastXhr;
$('#Field').autocomplete({
minLength: 2,
delay: 600,
source: function(request, response) {
var term = request.term;
if( term in cache ) {
response(cache[term]);
return;
}
// Abort previous access if one is defined
if (typeof lastXhr !== 'undefined' && lastXhr.hasOwnProperty("abort")) {
lastXhr.abort();
}
lastXhr = $.post('LoadData', function(data, status, xhr) {
cache[term] = data;
if(xhr === lastXhr) {
response(data);
// Set to undefined, we are done:
// helps when deciding to abort
lastXhr = undefined;
}
});
}
});
});
Upvotes: 3