Обнаружение отсутствия результатов при автозаполнении интерфейса jQuery
Прежде чем указать мне на них, да, я просмотрел полдюжины постов на эту тему, но я все еще не понимаю, почему это не работает.
Моя цель - определить, когда автозаполнение дает 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, которое не ссылается на количество результатов, никогда не срабатывает). Обработчик события open показывает правильное количество результатов (если они есть), а обработчики событий поиска и закрытия сообщают о размере результата, который всегда на один шаг позади.
Я чувствую, что упускаю что-то очевидное и ослепительно, но просто не вижу этого.
8 ответов
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
Я не смог найти простой способ сделать это с помощью API jQueryUI, однако вы могли бы заменить 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([]);
}
});
}
});
Кажется, что все игнорируют простой, встроенный способ: используйте событие messages: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.
Если вы используете удаленный источник данных (например, базу данных MySQL, PHP или что-то еще на стороне сервера), есть пара других более чистых способов справиться с ситуацией, когда нет данных для возврата клиенту (без необходимости какого-либо хаки или изменения кода UI основного кода).
Я использую 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.
}
});
После инициализации элемента автозаполнения установите опцию messages, если вы хотите использовать интервалы по умолчанию для индикации сообщений:
$(<yourselector>).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
, Если это там, вы идете, вы сделали свой день!:)
<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>
Я не понимаю почему source
параметра с пользовательским обратным вызовом недостаточно:
$("#autocomplete").autocomplete({
source: function (request, response) {
$.ajax({
url: "http://example.com/service.json",
data: {
q: this.term
},
success: function (data, textStatus, jqXHR) {
// data would be an array containing 0 or more items
console.log("[SUCCESS] search returned " + data.length + " item(s)");
response(data);
},
error: function (jqXHR, textStatus, errorThrown) {
// triggered when AJAX failed because of, for example, malformed JSON
console.log("[FAILURE] search returned error");
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);
}
});
},