如何在jQuery UI自动完成中实现“mustMatch”和“selectFirst”?
我最近将一些自动完成插件从助手生成的插件迁移到jQuery UI自动完成 。
如何在不修改核心自动完成代码本身的情况下使用callback和其他选项来实现“mustMatch”和“selectFirst”?
我想我解决了这两个function…
为了方便起见,我使用了一个通用的自定义select器:
$.expr[':'].textEquals = function (a, i, m) { return $(a).text().match("^" + m[3] + "$"); };
其余的代码:
$(function () { $("#tags").autocomplete({ source: '/get_my_data/', change: function (event, ui) { //if the value of the textbox does not match a suggestion, clear its value if ($(".ui-autocomplete li:textEquals('" + $(this).val() + "')").size() == 0) { $(this).val(''); } } }).live('keydown', function (e) { var keyCode = e.keyCode || e.which; //if TAB or RETURN is pressed and the text in the textbox does not match a suggestion, set the value of the textbox to the text of the first suggestion if((keyCode == 9 || keyCode == 13) && ($(".ui-autocomplete li:textEquals('" + $(this).val() + "')").size() == 0)) { $(this).val($(".ui-autocomplete li:visible:first").text()); } }); });
如果任何自动填充build议包含正则expression式使用的任何“特殊”字符,则必须在自定义select器的m [3]中转义这些字符:
function escape_regexp(text) { return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); }
并更改自定义select器:
$.expr[':'].textEquals = function (a, i, m) { return $(a).text().match("^" + escape_regexp(m[3]) + "$"); };
我用mustMatch这样简单的东西,它的工作原理。 我希望它可以帮助别人。
change: function (event, ui) { if (!ui.item) { $(this).val(''); } }
我想我得到了这个代码的mustMatch …需要通过testing:
<script type="text/javascript"> $(function() { $("#my_input_id").autocomplete({ source: '/get_my_data/', minChars: 3, change: function(event, ui) { // provide must match checking if what is in the input // is in the list of results. HACK! var source = $(this).val(); var found = $('.ui-autocomplete li').text().search(source); console.debug('found:' + found); if(found < 0) { $(this).val(''); } } }); }); </script>
我发现这个问题是有用的。
我想我会张贴我现在使用的代码(改编自Esteban Feldman的回答 )。
我已经添加了自己的mustMatch选项,并且在重置文本框值之前突出显示了问题。
change: function (event, ui) { if (options.mustMatch) { var found = $('.ui-autocomplete li').text().search($(this).val()); if (found < 0) { $(this).addClass('ui-autocomplete-nomatch').val(''); $(this).delay(1500).removeClass('ui-autocomplete-nomatch', 500); } } }
CSS
.ui-autocomplete-nomatch { background: white url('../Images/AutocompleteError.gif') right center no-repeat; }
我用来实现“mustMatch”的解决scheme:
<script type="text/javascript"> ... $('#recipient_name').autocomplete({ source: friends, change: function (event, ui) { if ($('#message_recipient_id').attr('rel') != $(this).val()) { $(this).val(''); $('#message_recipient_id').val(''); $('#message_recipient_id').attr('rel', ''); } }, select: function(event, ui) { $('#message_recipient_id').val(ui.item.user_id); $('#message_recipient_id').attr('rel', ui.item.label); } }); ... </script>
我发现了一个问题。 在build议列表处于活动状态时,即使该值与build议不符,您也可以提交表单。 为了消除这个我补充说:
$('form').submit(function() { if ($(".ui-autocomplete li:textEquals('" + $(this).val() + "')").size() == 0) { $(this).val(''); $("span").text("Select a valid city").show(); return false; } });
这样可以防止提交表单并显示消息。
这个JQuery-UI官方演示包括mustMatch,以及其他很酷的东西: http : //jqueryui.com/demos/autocomplete/#combobox
我已经更新它添加自动填充,以及其他一些事情。
使用Javascript:
/ *从http://jqueryui.com/demos/autocomplete/#combobox中窃取
*
*并添加了这些选项。
*
* - 自动填充(默认值:true):如果匹配,则select第一个值而不是清除
*
* - clearButton(默认值:true):添加一个“清除”button
*
* - adjustWidth(默认值:true):如果为true,则将自动填充宽度设置为与之相同
*旧的select。 (要求jQuery 1.4.4在IE8上工作)
*
* - uiStyle(默认值:false):如果为true,将添加类以便自动完成input
*采用jQuery-UI风格
* /
(function($){
$ .widget(“ui.combobox”,{
选项:{
自动填充:true,
clearButton:true,
adjustWidth:true,
uiStyle:false,
选中:null,
},
_create:function(){
var self = this,
select = this.element.hide(),
selected = select.children(“:selected”),
value = selected.val()? selected.text():“”,
found = false;
var input = this.input = $(“”)
.attr('title',''+ select.attr(“title”)+'')
.insertAfter(select)
.val(值)
.autocomplete({
延迟:0,
minLength:0,
source:function(request,response){
var matcher = new RegExp($ .ui.autocomplete.escapeRegex(request.term),“i”);
var resp = select.children(“option”).map(function(){
var text = $(this).text();
if(this.value &&(!request.term || matcher.test(text)))
返回{
label:text.replace(
新的RegExp(
“(?![^&;] +;)(?!] *)(”+
$ .ui.autocomplete.escapeRegex(request.term)+
“)(?![^] *>)(?![^&;] +;)”,“gi”
),“ $ 1 ”),
价值:文字,
选项:这个
};
});
found = resp.length> 0;
回应(resp);
},
select:function(event,ui){
ui.item.option.selected = true;
self._trigger(“selected”,event,{
item:ui.item.option
});
},
改变:function(event,ui){
如果(!ui.item){
var matcher = new RegExp(“^”+ $ .ui.autocomplete.escapeRegex($(this).val())+“$”,“i”),
有效=假;
select.children(“option”).each(function(){
if($(this).text()。match(matcher)){
this.selected = valid = true;
返回false;
}
});
if(!valid || input.data(“autocomplete”)。term ==“”){
//设置为第一个build议,除非空白或自动填充closures
varbuild议;
if(!self.options.autoFill || input.data(“autocomplete”)。term ==“”)found = false;
如果(find){
build议= jQuery(input.data(“autocomplete”)。部件())。find(“li:first”)[0];
var option = select.find(“option [text =”+ suggestion.innerText +“]”)。attr('selected',true);
$(本).VAL(suggestion.innerText);
input.data(“autocomplete”)。term = suggestion.innerText;
self._trigger(“selected”,event,{item:option [0]});
} else {
build议= {innerText:''};
select.find( “选项:select了”)removeAttr( “select”);。
$(本).VAL( '');
input.data(“autocomplete”).term ='';
self._trigger(“selected”,event,{item:null});
}
find回报;
}
}
}
});
if(self.options.adjustWidth){input.width(select.width()); }
if(self.options.uiStyle){
input.addClass(“ui-widget ui-widget-content ui-corner-left”);
}
input.data(“autocomplete”)._ renderItem = function(ul,item){
返回$(“ “)
.data(“item.autocomplete”,item)
.append(“”+ item.label +“”)
.appendTo(ul);
};
this.button = $(“”)
.attr(“tabIndex”,-1)
.attr(“title”,“显示所有项目”)
.insertAfter(input)
.button({
图标:{
主要:“ui-icon-triangle-1-s”
},
文字:错误
})
.removeClass(“ui-corner-all”)
.addClass(“ui-corner-right ui-button-icon”)
.click(function(){
//closures,如果已经可见
if(input.autocomplete(“widget”).is(“:visible”)){
input.autocomplete(“close”);
返回;
}
/ /解决一个错误(可能与#5265同样的原因)
$(this).blur();
//传递空string作为值来search,显示所有结果
input.autocomplete(“search”,“”);
input.focus();
});
if(self.options.clearButton){
this.clear_button = $(“”)
.attr(“tabIndex”,-1)
.attr(“标题”,“清除条目”)
.insertAfter(input)
.button({
图标:{
主要:“ui-icon-close”
},
文字:错误
})
.removeClass(“ui-corner-all”)
.click(function(event,ui){
select.find( “选项:select了”)removeAttr( “select”);。
input.val(“”);
input.data(“autocomplete”).term =“”;
self._trigger(“selected”,event,{item:null});
/ /解决一个错误(可能与#5265同样的原因)
$(this).blur();
});
}
},
destroy:function(){
this.input.remove();
this.button.remove();
this.element.show();
$ .Widget.prototype.destroy.call(this);
}
});
})(jQuery);
CSS(.hjq-combobox是一个包装跨度)
.hjq-combobox .ui-button {margin-left:-1px; }
.hjq-combobox .ui-button-icon-only .ui-button-text {padding:0; }
.hjq-combobox button.ui-button-icon-only {width:20px; }
.hjq-combobox .ui-autocomplete-input {margin-right:0; }
.hjq-combobox {white-space:nowrap;}
注意:此代码正在更新和维护在这里: https : //github.com/tablatom/hobo/blob/master/hobo_jquery_ui/vendor/assets/javascripts/combobox.js
也许这只是因为这是一个老问题,但我发现最简单的解决scheme已经在插件中,你只需要使用正确的function来访问它。
此代码将处理自动完成失去焦点并使用无效值的情况:
change: function(e, ui) { if (!ui.item) { $(this).val(""); } }
而这个代码就像来自bassistance的原始function一样,可以在input自动完成时处理没有匹配的情况:
response: function(e, ui) { if (ui.content.length == 0) { $(this).val(""); } }
这适用于静态数组源或JSON数据源。 结合autoFocus: true选项,它似乎以有效的方式做所有需要的事情。
您可能想要处理的最后一种情况是在文本框中使用无效值按下ESCAPE键时要执行的操作。 我所做的是使用第一个匹配结果的值。 这就是我的做法
首先,声明一个variables来保持最佳匹配。 在您的自动完成插件外执行此操作。
var bestMatch = "";
然后使用以下选项:
open: function(e, ui) { bestMatch = ""; var acData = $(this).data('uiAutocomplete'); acData.menu.element.find("A").each(function () { var me = $(this); if (me.parent().index() == 0) { bestMatch = me.text(); } }); }
最后,将以下事件添加到自动完成:
.on("keydown", function(e) { if (e.keyCode == 27) // ESCAPE key { $(this).val(bestMatch); } })
按下退出键时,您可以轻松地强制该字段为空。 你所要做的就是在按下键的时候将值设置为一个空string,而不是bestMatchvariables(如果你select清空字段,根本不需要bestMatchvariables)。
我做的有点不同,caching结果,并清除文本字段,如果某一项的结果数为零:
<script type='text/javascript'> function init_autocomplete( args ) { var resultCache = {}; var currentRequestTerm = null; var closeCallback = function() { // Clear text field if current request has no results if( resultCache[currentRequestTerm].length == 0 ) $(args.selector).val(''); }; var sourceCallback = function( request, responseCallback ) { // Save request term currentRequestTerm = request.term; // Check for cache hit // ... // If no cache hit, fetch remote data $.post( dataSourceUrl, { ... }, // post data function( response ) { // Store cache resultCache[request.term] = response; responseCallback( response ); } }; $(args.selector).autocomplete({ close: closeCallback, source: sourceCallback }); } </script>
Scott Gonzalez为jQueryUI自动完成编写了selectFirst扩展 (以及其他几个扩展 )。
- 斯科特·冈萨雷斯GitHub
- selectFirst Demo
基于接受的答案:
我的额外要求: 多个autocompletes , 不显眼的错误validation 。
change: function () { var target = $(this), widget = target.autocomplete('widget'), cond = widget.find('li:textEquals("' + target.val() + '")').length === 0; target.toggleClass('input-validation-error', cond); }
晚回复,但可能会帮助别人!
考虑到自动完成小部件中的两个事件
1)更改 – 当字段模糊且值更改时触发。
2)响应 – 当search完成并显示菜单时触发。
修改更改和响应事件,如下所示:
change : function(event,ui) { if(!ui.item){ $("selector").val(""); } }, response : function(event,ui){ if(ui.content.length==0){ $("selector").val(""); } }
希望这可以帮助!