如何在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,而不是bestMatch
variables(如果你select清空字段,根本不需要bestMatch
variables)。
我做的有点不同,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(""); } }
希望这可以帮助!