在 jQuery UI 自动完成上没有检测到结果
Posted
技术标签:
【中文标题】在 jQuery UI 自动完成上没有检测到结果【英文标题】:Detecting no results on jQuery UI autocomplete 【发布时间】:2011-06-10 18:39:05 【问题描述】:在你指出我之前,是的,我已经查看了关于这个主题的六篇文章,但我仍然不知道为什么这不起作用。
我的目标是检测自动完成何时产生 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!');
)
);
搜索本身运行良好,我可以毫无问题地显示结果。据我了解,我应该能够使用 autocomplete("result") 处理程序拦截结果。在这种情况下,它根本不会触发。 (即使是没有引用结果数量的通用警报或 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'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 函数(已更新以扩展自动完成的 @ 987654330@对象):
var __response = $.ui.autocomplete.prototype._response;
$.ui.autocomplete.prototype._response = function(content)
__response.apply(this, [content]);
this.element.trigger("autocompletesearchcomplete", [content]);
;
然后给autocompletesearchcomplete
事件绑定一个事件处理函数(contents是搜索的结果,一个数组):
$("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([]);
);
);
【讨论】:
@Andrew,知道如何使用 jQuery 访问“contents”数组中的元素吗??? @Bongs:你应该可以通过索引contents[0]
直接访问它
实际上是内容数组填充了用户名及其图像,并且无法通过指定索引值来访问它。但是想出了解决办法。不得不提到,contents[i].user.username... :) 感谢您的回复和很棒的解决方案...
上述解决方案也适用于基于相同 jQuery 插件的 PrimeFaces 自动完成 (2.2.x)。
在 JqueryUI 1.8.19 中,_response 函数被重命名为 __response。 (goo.gl/zAl88)。所以,$.ui.autocomplete.prototype._response 变成了 $.ui.autocomplete.prototype.__response【参考方案2】:
似乎每个人都忽略了简单的内置方法:使用 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 中添加的,作为实验性功能 (described here)。截至 2017 年 7 月,还不是documented in the API。
【讨论】:
【参考方案3】:如果您使用的是远程数据源(如 mysql 数据库、php 或服务器端的任何内容),则还有其他几种更简洁的方法可以处理没有数据返回客户端的情况(无需任何 hack 或核心代码 UI 代码更改)。
我使用 PHP 和 MySQL 作为远程数据源并使用 JSON 在它们之间传递信息。在我的情况下,如果 JSON 请求没有从服务器获得某种响应,我似乎会收到 jQuery 异常错误,所以我发现在没有数据时从服务器端返回一个空的 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.
);
【讨论】:
【参考方案4】:在初始化你的自动完成元素后,如果你想使用默认跨度来指示消息,请设置消息选项:
$(<yourselector>).autocomplete('option', 'messages',
noResults: 'myKewlMessage',
results: function( amount )
return amount + ( amount > 1 ? " results were" : " result was" ) + " found.";
);
注意:这是一个实验性 API(未记录)。 jQuery UI 开发人员仍在研究字符串操作和国际化的完整解决方案。
【讨论】:
【参考方案5】:玩了几个小时后,我终于找到了在 jQuery 自动完成中显示 No match found
的技巧。查看上面的代码并简单地添加一个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】: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);
);
,
【讨论】:
这个答案没有任何新的贡献,接受的答案具有相同的代码。【参考方案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");
);
);
【讨论】:
这个答案没有任何新的贡献,接受的答案具有相同的代码。以上是关于在 jQuery UI 自动完成上没有检测到结果的主要内容,如果未能解决你的问题,请参考以下文章
jQuery UI 自动完成:你如何启动一个异步进程并在它完成之前退出它