Подтвердить что ты не робот

Jquery ui autocomplete: как отменить медленный запрос ajax после ввода текста теряет фокус

Я использую поле автозаполнения пользовательского интерфейса JQuery, которое привязано к поиску ajax, который может быть довольно медленным в разы. Иногда пользователь будет отходить от поля ввода текста после того, как инициируется запрос ajax, но до возвращает вызов ajax. Когда это произойдет, всплывающее окно автозаполнения появляется, даже если текстовый ввод больше не имеет фокуса, и единственный способ отклонить всплывающее окно - это выбрать элемент (вместо того, чтобы переходить в другое поле).

Фактически этот jquery ui demo демонстрирует такое же поведение (например, введите "ariz" в текстовое поле, дождитесь "поиска" ', чтобы отобразиться, а затем выйдите из поля, прежде чем он вернет какие-либо результаты).

Одним из решений, которое работает (но похоже на хак), является проверка обратного вызова успеха ajax, чтобы увидеть, имеет ли текстовое поле все еще фокус, и если вы не вызываете response() с пустым списком, например:

        $( "#city" ).autocomplete({
        var elem = this.element;
        source: function( request, response ) {
            $.ajax({
                url: "http://ws.geonames.org/searchJSON",
                data: {name_startsWith: request.term},
                success: function( data ) {
                    if(!$(elem).is(':focus') {
                        response({});
                        return;
                    }
                    response( $.map( data.geonames, function( item ) {
                        return {
                            label: item.name + (item.adminName1 ? ", " + item.adminName1 : "") + ", " + item.countryName,
                            value: item.name
                        }
                    }));
                }
            });
        }
    });

Есть ли более изящное решение? В идеале я хотел бы отменить запрос ajax, как только пользователь уйдет от поля ввода текста.

4b9b3361

Ответ 1

$.ajax возвращает объект jqXHR, и этот объект предоставляет метод abort базовый объект XMLHttpRequest. Таким образом, вам просто нужно спрятать jqXHR и прервать запрос в нужное время. Что-то вроде этого возможно:

source: function(request, response) {
    var $this = $(this);
    var $element = $(this.element);
    var jqXHR = $element.data('jqXHR');
    if(jqXHR)
        jqXHR.abort();
    $element.data('jqXHR', $.ajax({
        // ...
        complete: function() {
            // This callback is called when the request completes
            // regardless of success or failure.
            $this.removeData('jqXHR');
            // And dismiss the search animation.
            response({});
        }
    });
}

И тогда вам нужно немного вещей на #city:

$('#city').blur(function() {
    var $this = $(this);
    var jqXHR = $(this).data('jqXHR');
    if(jqXHR)
        jqXHR.abort();
    $this.removeData('jqXHR');
});

Во время нормальной работы автозаполнения существует кратковременное размытие/фокус, но это происходит только тогда, когда кто-то выбирает что-то из списка; не должно быть запроса $.ajax, когда это происходит, поэтому нам не нужно беспокоиться об этом. Если я ошибаюсь, вы можете обходить его, используя таймер внутри обработчика blur и отменив таймер в обратном вызове focus (вы также можете сохранить идентификатор таймера в другом слоте .data()).

Я не тестировал это, но я уверен, что он сработает.