Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery ajax: process typeahead events in correct order?

I'm doing a webapp with html+jquery and a java rest-service backend. I have a textfield, with typeahead suggestions, so every character the user types in the field will trigger a server-round trip and update the list of typeahead suggestions.

Essential parts of the code:

    var showTypeaheadSuggestions = function(data) {
        // update ui-element ...
    }

    var displayFailure = function() {
        // update ui-element ...
    }

    var searchText = $("#searchText");
    var searchTextKeyup = function() {
        var txt = searchText.val();
        $.ajax({
            url : typeaheadUrl(txt),
            type : 'GET',
            dataType : 'json',
        }).done(showTypeaheadSuggestions).fail(displayFailure);
    }
    searchText.on('keyup', searchTextKeyup);

It's basically working. But I was thinking abt what happens if you type, for example, 2 letters "ab" (that will trigger first a request for "a" and then a request for "ab")...

Then, what happens if the "a" response takes a bit longer to process, and arrives after the "ab" response? Do I need to detect this in my code, to throw away the "a" response?

In http://api.jquery.com/jquery.ajax/ it does says:

Promise callbacks — .done(), .fail(), .always(), and .then() — are invoked, in the order they are registered.

What does that mean exactly? I was hoping this means $.ajax() would automatically handle the above scenario correct.

But when I do a small test (on the server-side I simply injected a 2 secs sleep-delay, only when the search-string is exactly "a"), it turns out it does not behave as I expected.

The typeahead list will first get updated with the "ab" response, and then when the "a" response arrives, it also updates, so the typeahead list gets the wrong suggestions.

What is the established way to handle this correctly?

like image 902
Rop Avatar asked Sep 26 '22 12:09

Rop


1 Answers

There's another approach if you want to keep the server side code without changes. You can actually wrap the return functions inside a class and create instances for each request, then store the latest instance in a global scoped variable and check if the owner of the invoked method does match the latest instance:

var lastRequest;
var searchText = $("#searchText");

function requestClass()
{
    var that = this;

    this.showTypeaheadSuggestions = function(data) {
        //Update ui-element
        if (lastRequest == that)
            console.log('suggestions retrieved: ' + data);
        else
            console.log('this response (' + data + ') is ignored');
    };

    this.displayFailure = function() {
        //Update ui-element
        console.log('failure');
    };
}

var searchTextKeyup = function() {
    var request = new requestClass();
    lastRequest = request;

    var txt = searchText.val();
    $.ajax({
        url : typeaheadUrl(txt),
        type : 'GET',
        dataType : 'json',
    }).done(request.showTypeaheadSuggestions).fail(request.displayFailure);
}

searchText.on('keyup', searchTextKeyup);

I have tested this with the small-test you proposed in the question (adding a 2 seconds delay when the search string does match the 'a' character) and the result is the following:

suggestions retrieved: ab
this response (a) is ignored
like image 151
Ivan De Paz Centeno Avatar answered Oct 04 '22 17:10

Ivan De Paz Centeno