jQuery UI Autocomplete: Aborting the request
Asked Answered
B

2

6

I'm using the callback version of the source option which performs an ajax request. I figure if a user types a bunch of letters in rapid succession before an ajax request completes, we should abort the old one and only use the new one. I'm assuming the URL version for the source parameter would do this automatically, but since I'm using a custom callback, I'd have to do that manually.

So here's what I've got:

$('#myselector').autocomplete({
    source: function(request, response) {
        var data = {};
        if($(this).data('xhr')) {
            console.log('aborting...');
            $(this).data('xhr').abort();
        }
        // *snip* add some stuff to data
        $(this).data('xhr', $.ajax({
            url: '/ajax/major_city',
            dataType: 'json',
            data: data,
            success: function(data, textStatus, $xhr) {
                response(data);
            },
            complete: function($xhr, textStatus) {
                console.log(textStatus);
                if(textStatus === 'abort') {
                    console.log('aborted!');
                    response([]);
                }
            }
        }));
    },
// ....

So, whenever the "source" callback is triggered, it checks if the XHR element exists for that input (will be undefined the first time), and if so, aborts it (side question: how can I check if the request is complete? No sense trying abort requests that have already completed).

But the docs say:

It's important when providing a custom source callback to handle errors during the request. You must always call the response callback even if you encounter an error. This ensures that the widget always has the correct state.

So, towards the bottom of my code you'll see that I (attempt to) check if the request has been aborted, and if so, I return an empty list. But that "aborted!" log never seems to be called. It always says "success" even when it gets aborted. Why's that?


Edit: Just tried outputting $(this).data('xhr').readyState. It never seems to be less than 4 which suggests to me that source isn't called again until the last request returns a response. Which is a shame, because we could abort the requests early and speed up the response time a bit...

Basiliabasilian answered 24/6, 2011 at 1:26 Comment(1)
There is a good answer to a similar question hereFederalism
G
4

bdparrish has the right idea

Increase the time the plugin waits before sending the request:

$( ".selector" ).autocomplete({ delay: 500 }); //default is 300

This way you will only send the request once you suspect the user has finished typing. It's better to make less http requests than make many and cancel them.

-Lededje

Grind answered 17/10, 2012 at 21:40 Comment(2)
This is not a real solution IMO. It might help mitigate the problem, but no matter what you set the delay to, they might hit another key a ms later. Also, you're sacrificing response time to reduce the number of requests. I can type at about 100 WPM which I think roughly equates to 1 character every 150ms, thus I would like to set the delay only slightly higher than that. Lastly, regardless of the legitimacy of this answer, you're not addressing the issue of why an abort isn't firing the callback.Basiliabasilian
If you have implemented the plugin correctly all requests will be trapped within the complete function. It is then up to you to "abort" the code from running when another key is pressed. The status code would not be abort because you haven't told the server you are doing so. If you want it to work like that, catch the successful return of the request and then do nothing with it.Grind
W
0

Is there a reason that you can't set the time interval to wait for the user to "seem" like they are finished typing? The 'delay' option sets the milliseconds that it will wait after the last letter is typed before searching.

Also, the response would still be a success even if you return 'abort' from the server. because the request did not error out on the server. you return the value 'abort' i am assuming.

Wag answered 24/6, 2011 at 1:42 Comment(2)
I'm not quite sure what you're trying to say with your first paragraph. I want to lower the delay and abort the old requests to improve response times. If a user is typing too slow (exceeding the delay), it might fire an ajax request just before he hits the next letter. That request is now no longer valid, so it should be aborted immediately so that we don't have to wait for that request to finish before starting the next one.Basiliabasilian
No, I'm not returning 'abort'. The docs specifically say textStatus can be one of "success", "notmodified", "error", "timeout", "abort", or "parsererror". I'm assuming I would get a textStatus of "abort" when I abort the request, so that's what I was listening for. But seeing as that I'm never given a chance to abort, because the next event isn't even fired until the previous one successfully returns, this point is moot.Basiliabasilian

© 2022 - 2024 — McMap. All rights reserved.