Jquery ajax: typeahead event process in the correct order?

I am doing a webapp with html + jquery and a java support service backend. I have a text box with sentences of type, so that each character that the user enters into the field initiates a workaround and updates the list of sentences of type

.

The main 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 basically works. But I was thinking about what would happen if you type, for example, 2 letters "ab" (this will first call the query "a" and then the query "ab") ...

Then, what happens if the answer "a" takes a little longer to process and comes after the answer "ab"? Do I need to detect this in my code to discard the answer "a"?

At http://api.jquery.com/jquery.ajax/ he says:

Promise callbacks -.done () ,. fail () ,. always () and .then () are called in the order in which they are registered.

What does it mean? I was hoping this means that $ .ajax () will automatically handle the above script correctly.

But when I do a little test (on the server side, I just entered a 2 s sleep delay, only when the search bar was exactly "a") it turns out that it does not behave as I expected.

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

What is the established way to handle this correctly?

+5
source share
4 answers

There is another approach if you want to keep the server side code intact. In fact, you can wrap the returned functions inside the class and create instances for each request, and then save the last instance in the global cloud variable and check if the owner of the called method matches the last 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 tested this with the small test that you suggested in the question (adding a delay of 2 seconds when the search bar matches the character "a"), and the result is as follows:

 suggestions retrieved: ab this response (a) is ignored 
+1
source

One of the ways in which I ran into this problem was to assign an identifier for each call, and pass it as an identifier to the server. When your server processes it, it will then send the result back along with it.

Then, every time the client-side code is executed, the identifier is incremented. For instance:

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

Then, when you receive a response, you check if the identifier is current. In case the user fires two events at once, your ajax event will fire twice, once with callback_id = 0 and one with callback_id = 1 .

The last thing you need to do is an if statement that updates your TypeaheadSuggestions if callback_id is the most recent, comparing the identifier sent back from your server response.

+1
source

You must compare the new input text with the text that you sent, and if he wants to find the user, you will show him, otherwise nothing will happen with the answer.

For instance:

 var searchText = $("input").val() $.ajax({ .... data: {searchText : searchText} success: funtion(){ if($("input").val()==searchText){ //SHOW RESULTS } } }) 
+1
source

The Promises interface immediately returns a Promise object to you so you can use a different syntax for the callback.

Instead:

 asyncCall(callback); 

You can use:

 asyncCall() .then(callback); 

And you can link them:

 authorizeAccount() .then(getNames) .then(processNames); 

processNames will be executed in the order they are registered - processNames will wait for getNames first.

The “installed” way to handle this “correctly” is probably to add debugging on the client side, so that only the entire request (“request” instead of “q”, “qu” 'que' ...) is processed when the word is entered: http://underscorejs.org/#debounce with a timeout expiring response if it takes too much time to return.

+1
source

Source: https://habr.com/ru/post/1233488/


All Articles