1

I am trying to build an auto-complete UI. There is an input whose on keyup function does an ajax call to server to fetch the most relevant data. But if user types a word which is, say 10 character long, so for each keyup one ajax call is made and my dialogue box refreshes 10 times.

I have tried using abort() for the ajax call. When I do an abort to previous ajax call, the call is not made but still it waits for 10 calls before executing the last one, which makes the user experience very bad.

So is there a way to execute just the current ajax call without any delay from the previous ones?

A part of my code:

var request_autocomplete=jQuery.ajax({});
$('.review_autocomplete').keyup(function() {
    request_autocomplete.abort();
    request_autocomplete=jQuery.ajax({
        // DO something
    });
});
Lucas Trzesniewski
  • 50,214
  • 11
  • 107
  • 158
Prateek Chandan
  • 107
  • 2
  • 11
  • possible duplicate of [jQuery autocomplete, Can I have the previous ajax calling stopped when I raise a new one?](http://stackoverflow.com/questions/4121963/jquery-autocomplete-can-i-have-the-previous-ajax-calling-stopped-when-i-raise-a) – Farshad Aug 29 '14 at 23:51
  • I am not using JQuery autocomplete – Prateek Chandan Aug 30 '14 at 00:18

4 Answers4

1

OP, there are two parts to this. The first is your abort, which it seems that you already have.

The second is to introduce forgiveness into the process. You want to fire when the user stops typing, and not on every key press.

You need to use both keyUp and keyDown. On keyUp, set a timeout to fire your submit. Give it perhaps 700ms. On KeyDown, clear the timeout.

    var request_autocomplete=jQuery.ajax({});
    var forgiveness;

    // first your AJAX routine as a function
    var myServiceCall = function() {
       request_autocomplete.abort();
       request_autocomplete=jQuery.ajax({
            // DO something
    }

    // keyup 
    $('.review_autocomplete').keyup(function() {
        forgiveness = window.setTimeout(myServiceCall, 700);

      });
    });

    // key down
    $('.review_autocomplete').keydown(function() {
        window.clearTimeout(forgiveness);

      });
    });

What this will do is constantly set a timeout to fire every time a key is up, but each time a key is down it will cancel that timeout. This will have the effect of keeping your service call from firing until the user has stopped typing, or paused too long. The end result is that you will wind up aborting a much smaller percentage of your calls.

Thomas W Tupper
  • 625
  • 1
  • 6
  • 17
0

you can implement the way you asked in your question is preventing for example 3 calls as below :

var calls = 0;
$('.review_autocomplete').keyup(function() {
    if (calls >3) {
        request_autocomplete.abort();
        request_autocomplete=jQuery.ajax({
            // DO something
        });
        calls = 0;
    }
    calls++;
});

but this way not recommended because when user wants to types sample while user types samp at p ajax call fire up. and when user type l and e nothing happen !

If you are using jquery Autocomplete you can using

minLenght so you can check current lenght of text box and when user typed at least 3 character then you must call the ajax request.

delay (between last keystroke and ajax call. Usually 2-300ms should do)

and using AjaxQueue

after a quick search about this issue I have found this link that shows another way to prevent multiple ajax calls for autocomplete by using cache

Community
  • 1
  • 1
Farshad
  • 1,465
  • 1
  • 9
  • 12
  • This wont work I guess because the typing speed of user will be way more faster than the fetching time from server. And thus it will result in timeout of all my requests – Prateek Chandan Aug 29 '14 at 23:16
  • I think this question is duplicate of [http://stackoverflow.com/questions/4121963/jquery-autocomplete-can-i-have-the-previous-ajax-calling-stopped-when-i-raise-a](http://stackoverflow.com/questions/4121963/jquery-autocomplete-can-i-have-the-previous-ajax-calling-stopped-when-i-raise-a) – Farshad Aug 29 '14 at 23:51
0

You could use a globalTimeout variable that you reset with setTimeout() and clearTimeout().

var globalTimeout;
$('.review_autocomplete').keydown(function(){
  if(globalTimeout)clearTimeout(globalTimeout);
}).keyup(function(){
  globalTimeout = setTimeoout(function(){
    $.ajax({/* you know the drill */});
  }, 10);
});

This way the timeout is cleared whenever your Client pushes a keydown, yet the timeout is set again as soon as the your Client releases a key onkeyup, therefore $.ajax() will only be called if there's no key action, after 10 milliseconds in this case. I admit that this won't stop an $.ajax() call that has already been made, however it probably won't matter because they happen pretty fast, and because this example prevents future $.ajax() calls as long as the Client keeps typing.

StackSlave
  • 10,613
  • 2
  • 18
  • 35
0

Try

var count = {
    "start": 0,
    // future , by margin of `count.timeout`
    "complete": 0,
    // if no `keyup` events occur ,
    // within span of `count.timeout` 
    // `request_autocomplete()` is called
    // approximately `2` seconds , below ,
    // adjustable 
    "timeout" : 2
};
$('.review_autocomplete')
.focus()
.on("keyup", function (e) {
    elem = $(this);
    window.clearInterval(window.s);
    window.s = null;
    var time = function () {
        var t = Math.round($.now() / 1000);
        count.start = t;
        count.complete = t + count.timeout;
    };
    time();
    var request_autocomplete = function () {

        return jQuery.ajax({
            url: "/echo/json/",
            type: "POST",
            dataType: "json",
            data: {
                json: JSON.stringify({
                    "data": elem.val()
                })
            }
            // DO something
        }).done(function (data) {
            window.clearInterval(s);
            console.log("request complete", data);
            $("body").append("<br /><em>" + data.data + "</em>");
            elem.val("");
            count.start = count.complete = 0;
            console.log(count.start, count.complete);
        });
    };
    window.s = setInterval(function () {
        if (Math.round($.now() / 1000) > count.complete) {
            request_autocomplete();
            console.log("requesting data");
        };
    // increased to `1000` from `501`
    }, 1000);

});

jsfiddle http://jsfiddle.net/guest271314/73yrndwy/

guest271314
  • 1
  • 15
  • 104
  • 177