Dismissile
Dismissile

Reputation: 33071

Multiple Autocomplete Calls - jQuery

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

Answers (4)

Robert Fransdonk
Robert Fransdonk

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

Hamdi Douss
Hamdi Douss

Reputation: 1113

I would just make :

if(xhr === lastXhr) {
    response(data);
} else {
    return false;
}

Upvotes: 0

Jonny
Jonny

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

Jeff B
Jeff B

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

Related Questions