如何在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(""); } } 

    希望这可以帮助!