Не обнаружено никаких результатов при автозаполнении 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, который не ссылается на количество результатов, никогда не срабатывает). Открытый обработчик событий показывает правильное количество результатов (когда есть результаты), а обработчики событий поиска и закрытия сообщают о размере результата, который всегда находится на одном шаге.

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

jQueryUI 1.9

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

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

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

 $(function() { $("input").autocomplete({ source: /* */, response: function(event, ui) { // ui.content is the array that's 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 по умолчанию ( обновленную для расширения объекта 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([]); } }); } }); 

Если вы используете удаленный источник данных (например, базу данных 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. } }); 

Кажется, что все игнорируют простой, встроенный способ: используйте сообщения: 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 .

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

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

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

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

 
   Enter code here 

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

Сценарий на стороне сервера должен выдавать действительный 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([]); } }); } }); 
 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"); } }); } }); } 
 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); } }); }, 
Давайте будем гением компьютера.