Scott
Scott

Reputation: 1310

JQuery ajax .abort()

  1. User clicks on search box
  2. User types a surname
  3. If the texbox lengh is more than 2 characters ajax webservice is called

The problem I have is with slow databases with thousands of records...

I can type "mcm" and wait and it will return 40 results in 3 seconds. I can continue to type "mcmil" and it will return 11 results in 1 second.

The problem is if I type "mcmil" all at once from scratch, i can visibly see the first 11 results then the results jump as the results for "mcm" and "mcmi" are loaded in, presumably as they are slower.

When the .keyup fires, I need a way to detect if a .ajax request is currently being made and cancel it before making the new one.

$('#employeesearchbox').keyup(function () {

    if ($("#employeesearchbox").val().length > 2) {

        $.ajax({
            type: 'POST',
            url: './webservices/Contacts.asmx/ContactsDirectorySearch',
            data: JSON.stringify({ Surname: $("#employeesearchbox").val() }),
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            success: function (msg) {
                var employees = msg.d;
                $.each(employees, function (index, employee) {
                    $('#message').append("<li><a href='javascript:void(0);' class='response_object'>" + employee.Firstname + " " + employee.Department + "</a></li>");
                });
            },
            error: function (xhr, ajaxOptions, thrownError) {
                console.error("The error was: " + xhr.responseText);
            }
        });

    }

});

I had a look at this post: abort-ajax-requests-using-jquery

It cancels the request directly after the .ajax where as i probably want to test on next key press and when i add this code i get "object undefined" error - as the object doesnt already exist!

please help

thanks

var xhr = $.ajax({
 ...
});

//kill the request
xhr.abort()

Upvotes: 0

Views: 842

Answers (3)

John C
John C

Reputation: 3112

To expand on my comment -

I'd be thinking about putting your ajax in maybe a half second setTimeout which is cleared with each new keypress. Most people will type more quickly than that. Also look at the answers to this question - Average Inter-Keypress time when typing and maybe look at the link in the comments of the accepted answer

For example -

var delaySearch;
$('#employeesearchbox').keyup(function () {
  if ($("#employeesearchbox").val().length > 2) {
    clearTimeout(delaySearch);
    delaySearch = setTimeout(function() {
      $.ajax({
        type: 'POST',
        url: './webservices/Contacts.asmx/ContactsDirectorySearch',
        data: JSON.stringify({ Surname: $("#employeesearchbox").val() }),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        success: function (msg) {
          var employees = msg.d;
          $.each(employees, function (index, employee) {
            $('#message').append("<li><a href='javascript:void(0);' class='response_object'>" + employee.Firstname + " " + employee.Department + "</a></li>");
          });
        },
        error: function (xhr, ajaxOptions, thrownError) {
          console.error("The error was: " + xhr.responseText);
        }
      });
    }, 500);
  }
});

I've set the timeout to 500ms but but you might want to go a little longer depending on the performance of your database and your intended audience.

Upvotes: 1

Scott
Scott

Reputation: 1310

Thanks to @robert, here's the working code.

xhr is declaired as null outsite .keyup scope after keypress, i can check if it's not equal null and cancel it with .abort()

var xhr = null;

$('#employeesearchbox').keyup(function () {

    if ($("#employeesearchbox").val().length > 2) {

        if (xhr == null) {
            console.error("null");
        } else {
            //kill the request
            xhr.abort()
        }

        xhr = $.ajax({
            type: 'POST',
            url: './webservices/Contacts.asmx/ContactsDirectorySearch',
            data: JSON.stringify({ Surname: $("#employeesearchbox").val() }),
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            success: function (msg) {
                var employees = msg.d;
                $.each(employees, function (index, employee) {
                    $('#message').append("<li><a href='javascript:void(0);' class='response_object'>" + employee.Firstname + " " + employee.Department + "</a></li>");
                });
            },
            error: function (xhr, ajaxOptions, thrownError) {
                console.error("The error was: " + xhr.responseText);
            }
        });

    }

});

Upvotes: 0

bingo
bingo

Reputation: 2308

What about something along these lines? Create an id for each request sent pass it to the server and send it back from the server. Only update the document if the request isn't too old.

I still think you should consider debouncing these requests Basically, don't send the request until a 300 milliseconds until after they are done typing or something.

    var requestid = 0;
    $('#employeesearchbox').keyup(function () {

        if ($("#employeesearchbox").val().length > 2) {
            requestid++;
            $.ajax({
                type: 'POST',
                url: './webservices/Contacts.asmx/ContactsDirectorySearch',
                data: JSON.stringify({ Surname: $("#employeesearchbox").val(), requestid: requestid }),
                contentType: 'application/json; charset=utf-8',
                dataType: 'json',
                error: function (xhr, ajaxOptions, thrownError) {
                    console.error("The error was: " + xhr.responseText);
                }
            }).done(function(msg){
                if(msg.requestid >= requestid){
                    var employees = msg.d;
                    $.each(employees, function (index, employee) {
                        $('#message').append("<li><a href='javascript:void(0);' class='response_object'>" + employee.Firstname + " " + employee.Department + "</a></li>");
                    });  
                }
            });

        }

    });

Upvotes: 0

Related Questions