Не обнаружено никаких результатов при автозаполнении jQuery UI

Прежде чем указать мне на них, да, я просмотрел полдюжины сообщений по этой теме, но я все еще не согласен с тем, почему это не работает.

Моя цель - обнаружить, когда автозаполнение дает 0 результатов. Здесь код:

 $.ajax({
   url:'sample_list.foo2',
   type: 'get',
   success: function(data, textStatus, XMLHttpRequest) {
      var suggestions=data.split(",");

  $("#entitySearch").autocomplete({ 
    source: suggestions,
    minLength: 3,
    select: function(e, ui) {  
     entityAdd(ui.item.value);
     },
    open: function(e, ui) { 
     console.log($(".ui-autocomplete li").size());
     },
    search: function(e,ui) {
     console.log("search returned: " + $(".ui-autocomplete li").size());

    },
    close: function(e,ui) {  
     console.log("on close" +  $(".ui-autocomplete li").size());    
     $("#entitySearch").val("");
    }
   }); 

  $("#entitySearch").autocomplete("result", function(event, data) {

   if (!data) { alert('nothing found!'); }

  })
 }
}); 

Сам поиск отлично работает, я могу получить результаты, чтобы они отображались без проблем. Насколько я понимаю, я должен перехватить результаты с помощью обработчика автозаполнения ( "результат" ). В этом случае он никогда не срабатывает вообще. (Даже общее предупреждение или console.log, который не ссылается на количество результатов, никогда не срабатывает). Открытый обработчик событий показывает правильное количество результатов (когда есть результаты), а обработчики событий поиска и закрытия сообщают о размере результата, который всегда находится на одном шаге.

Я чувствую, что мне не хватает чего-то очевидного и вопиющего, но я просто этого не вижу.

Ответ 1

jQueryUI 1.9

jQueryUI 1.9 благословил виджет автозаполнения с событием response, который мы можем использовать, чтобы обнаружить, не были ли возвращены результаты:

Запуск после завершения поиска, прежде чем отобразится меню. Полезно для локальных манипуляций с данными предложения, где необязательный обратный вызов опции источника не требуется. Это событие всегда запускается, когда поиск завершается, даже если меню не будет отображаться, потому что результатов нет или автозаполнение отключено.

Итак, имея в виду, взлом, который мы должны были сделать в jQueryUI 1.8, заменяется на:

$(function() {
    $("input").autocomplete({
        source: /* */,
        response: function(event, ui) {
            // ui.content is the array that about to be sent to the response callback.
            if (ui.content.length === 0) {
                $("#empty-message").text("No results found");
            } else {
                $("#empty-message").empty();
            }
        }
    });
});​

Пример: http://jsfiddle.net/andrewwhitaker/x5q6Q/


jQueryUI 1.8

Я не мог найти простой способ сделать это с помощью jQueryUI API, однако вы могли бы заменить функцию autocomplete._response на свой собственный, а затем вызвать функцию jQueryUI по умолчанию (обновленную для расширения объекта autocomplete prototype):

var __response = $.ui.autocomplete.prototype._response;
$.ui.autocomplete.prototype._response = function(content) {
    __response.apply(this, [content]);
    this.element.trigger("autocompletesearchcomplete", [content]);
};

И затем привяжите обработчик события к событию autocompletesearchcomplete (содержимое - результат поиска, массив):

$("input").bind("autocompletesearchcomplete", function(event, contents) {
    $("#results").html(contents.length);
});

Что здесь происходит, так это то, что вы сохраняете функцию автозаполнения response для переменной (__response), а затем используете apply чтобы позвонить ему снова. Я не могу представить никаких негативных последствий этого метода, так как вы вызываете метод по умолчанию. Поскольку мы модифицируем прототип объекта, это будет работать для всех автозаполненных виджетов.

Вот рабочий пример: http://jsfiddle.net/andrewwhitaker/VEhyV/

В моем примере используется локальный массив в качестве источника данных, но я не думаю, что это имеет значение.


Обновление: Вы можете также обернуть новую функциональность в свой собственный виджет, расширив функциональность автозаполнения по умолчанию:

$.widget("ui.customautocomplete", $.extend({}, $.ui.autocomplete.prototype, {

  _response: function(contents){
      $.ui.autocomplete.prototype._response.apply(this, arguments);
      $(this.element).trigger("autocompletesearchcomplete", [contents]);
  }
}));

Изменение вашего вызова с .autocomplete({...}); на:

$("input").customautocomplete({..});

И затем свяжитесь с пользовательским событием autocompletesearchcomplete позже:

$("input").bind("autocompletesearchcomplete", function(event, contents) {
    $("#results").html(contents.length);
});

См. пример здесь: http://jsfiddle.net/andrewwhitaker/VBTGJ/


Поскольку этот вопрос/ответ получил некоторое внимание, я подумал, что обновляю этот ответ еще одним способом для этого. Этот метод наиболее полезен, если на странице есть только один виджет автозаполнения. Этот способ выполнения может быть применен к виджету автозаполнения, который использует удаленный или локальный источник:

var src = [...];

$("#auto").autocomplete({
    source: function (request, response) {
        var results = $.ui.autocomplete.filter(src, request.term);

        if (!results.length) {
            $("#no-results").text("No results found!");
        } else {
            $("#no-results").empty();
        }

        response(results);
    }
});

Внутри if вы можете поместить свою пользовательскую логику, когда результаты не будут обнаружены.

Пример: http://jsfiddle.net/qz29K/

Если вы используете удаленный источник данных, скажите что-то вроде этого:

$("#auto").autocomplete({
    source: "my_remote_src"
});

Затем вам нужно будет изменить свой код, чтобы вы сами вызывали вызов AJAX и могли обнаруживать, когда возвращаются 0 результатов:

$("#auto").autocomplete({
    source: function (request, response) {
        $.ajax({
            url: "my_remote_src", 
            data: request,
            success: function (data) {
                response(data);
                if (data.length === 0) {
                    // Do logic for empty result.
                }
            },
            error: function () {
                response([]);
            }
        });
    }
});

Ответ 2

Если вы используете удаленный источник данных (например, базу данных MySQL, PHP или что-то еще на стороне сервера), есть пару других более чистых способов справиться с ситуацией, когда нет данных для возврата клиенту (без необходимости изменения каких-либо хаков или изменения кода кода кода ядра).

Я использую PHP и MySQL в качестве удаленного источника данных и JSON для передачи информации между ними. В моем случае я, казалось, получал ошибки исключения jQuery, если запрос JSON не получил какого-либо ответа с сервера, поэтому мне было проще просто вернуть пустой ответ JSON с серверной стороны, когда нет данных, а затем обрабатывать клиент ответ оттуда:

if (preg_match("/^[a-zA-Z0-9_]*$/", $_GET['callback'])) {//sanitize callback name
    $callback = $_GET['callback'];
} else { die(); }

die($callback . "([])");

Другим способом было бы вернуть флаг в ответе от сервера, чтобы указать, что нет соответствующих данных и выполнять действия клиентской стороны на основе присутствия (и/или значения) флага в ответе. В этом случае ответ сервера будет примерно таким:

die($callback . "([{'nodata':true}])");

Затем на основе этого флага действия могут выполняться на стороне клиента:

$.getJSON('response.php?callback=?', request, function (response) {
    if (typeof response[0].nodata !== 'undefined' && response[0].nodata === true) {
        alert('No data to display!');
    } else {
        //Do whatever needs to be done in the event that there is actually data to display.
    }
});

Ответ 3

Кажется, что все игнорируют простой, встроенный способ: используйте сообщения: noResults.

$('#field_name').autocomplete({
  source: $('#field_name').data('autocomplete-source'),
  messages: {
    noResults: function(count) {
      console.log("There were no matches.")
    },
    results: function(count) {
      console.log("There were " + count + " matches")
    }
  }
})

Эта функция была добавлена ​​в jQuery 1.9 в качестве экспериментальной функции (описанной здесь). По состоянию на июль 2017 года еще не задокументировано в API.

Ответ 4

После инициализации вашего элемента автозаполнения установите параметр сообщений, если вы хотите использовать интервалы по умолчанию для отображения сообщения:

$(<yourselector>).autocomplete('option', 'messages', {
    noResults: 'myKewlMessage',
    results: function( amount ) {
        return amount + ( amount > 1 ? " results were" : " result was" ) + " found.";
    }
});

ПРИМЕЧАНИЕ. Это экспериментальный API (не документированный). Разработчики jQuery UI по-прежнему изучают полное решение для струнных манипуляций и интернационализации.

Ответ 5

После нескольких часов игры я наконец нашел трюк, чтобы отобразить No match found в автозапуске jQuery. Посмотрите на приведенный выше код и просто добавьте div, в моем случае #ulNoMatch и его стиль установлен на displap:none. В методе успешного выполнения обратного вызова проверьте, имеет ли возвращенный массив length == 0. Если это ты туда, ты сделал свой день!:)

<pre><div class="ui-widget1" style="width: auto;">
    <asp:TextBox ID="txtSearch" class="tb" runat="server" Width="150px">
    </asp:TextBox>
    <ul id="ulNoMatch" class="ui-autocomplete ui-menu ui-widget1 ui-widget1-content ui-corner-all"
        role="listbox" aria-activedescendant="ui-active-menuitem" style="z-index: 16;
        display: none; width: 150px;">
        <li class="ui-menu-item" role="menuitem"><a class="ui-corner-all" tabindex="-1">No Matches
            Found</a></li>
    </ul>
    </div><pre>
<b>
<b>

Enter code here

<script>
    $(function () {
        $("input[id$='txtSearch']").autocomplete({
            source: function (request, response) {
                $.ajax({
                    url: "splah.aspx/GetByName",
                    data: "{ 'strName': '" + request.term.trim() + "' }",
                    dataType: "json",
                    type: "POST",
                    //cacheLength: 1,
                    contentType: "application/json; charset=utf-8",
                    dataFilter: function (data) {
                        return data; },
                    success: function (data) {
                        var found = $.map(data.d, function (item) {
                            return {
                                value: item.Name,
                                id: item.id
                            }
                         });

                         if (found.length == 0)
                         {
                             $("#ulNoMatch").show();
                         }
                         else
                         {
                             $("#ulNoMatch").hide();
                         }
                         response(found);
                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {
                        alert(textStatus);
                    }
                });
            },
            select: function (event, ui) {
                $("input[id$='txtSearch']").val(ui.item.label);
                $("input[id$='txtID']").val(ui.item.id);
                return false;
            },
            minLength: 1
        });
    });
</script>

Ответ 6

Я не понимаю, почему параметр source с пользовательским обратным вызовом недостаточно. Предполагая, что мы используем службу JSON (P), просто помните следующее:

Серверная сторона script должна выдавать действительный JSON, даже если результаты не найдены - и [] действителен JSON.

Документация для параметра source предполагает, что:

Ответный ответ, который ожидает один аргумент: данные для предложить пользователю. Эти данные должны быть отфильтрованы на основе предоставленный термин, и может быть в любом из форматов, описанных выше для простые локальные данные. Это важно при предоставлении настраиваемого источника обратный вызов для обработки ошибок во время запроса. Вы всегда должны звонить ответный ответ, даже если вы столкнулись с ошибкой. Это обеспечивает что виджет всегда имеет правильное состояние.

Сохраняя вышеуказанные две точки, должно быть достаточно:

$("#autocomplete").autocomplete({
    source: function (request, response) {
        $.ajax({
            url: "http://example.com/service.json",
            data: {
                q: this.term
            },
            success: function (data, textStatus, jqXHR) {
                // data must be an array containing 0 or more items
                console.log("[SUCCESS] " + data.length + " item(s)");
                response(data);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                // triggered when AJAX failed because of, for example, malformed JSON
                console.log("[ERROR] n/a item(s)");
                response([]);
            }
        });
    }
});

Ответ 7

function SearchText() {
 $(".autosuggest").autocomplete({
   source: function (request, response) {
    $.ajax({
     type: "POST",
     contentType: "application/json; charset=utf-8",
      url: "Default.aspx/GetAutoCompleteData",
      data: "{'username':'" + document.getElementById('txtSearch').value + "'}",
        dataType: "json",
        success: function (data.d) {
        if ((data.d).length == 0) {
         alert("no result found");
          }
           response(data.d);
         },
         error: function (result) {
              alert("Error");
         }
         });
        }
     });
  }

Ответ 8

The easiest straight forward way to do it.

$("#search-box").autocomplete({
                    minLength: 2,
                    source:function (request, response) {
                        $.ajax({
                            url: urlPref + "/Api/SearchItems",
                            data: {
                                term: request.term
                            },
                            success: function (data) {
                                if (data.length == 0) {
                                    data.push({
                                        Id: 0,
                                        Title: "No results found"
                                    });
                                }
                                response(data);
                            }
                            });
                        },