如何在 jQuery UI 自动完成中实现“mustMatch”和“selectFirst”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2587378/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to implement "mustMatch" and "selectFirst" in jQuery UI Autocomplete?
提问by dochoffiday
I recently migrated a few of my Autocomplete plugins from the one produced by bassistanceto the jQuery UI autocomplete.
我最近将我的一些 Autocomplete 插件从bassistance制作的插件迁移到了jQuery UI autocomplete。
How can the "mustMatch" and "selectFirst" be implemented with just callbacks and other options without modifying the core autocomplete code itself?
如何在不修改核心自动完成代码本身的情况下仅使用回调和其他选项来实现“mustMatch”和“selectFirst”?
回答by dochoffiday
I think I solved both features...
我想我解决了这两个功能......
To make things easier, I used a common custom selector:
为了让事情更容易,我使用了一个通用的自定义选择器:
$.expr[':'].textEquals = function (a, i, m) {
return $(a).text().match("^" + m[3] + "$");
};
The rest of the code:
其余代码:
$(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());
}
});
});
If any of your autocomplete suggestions contain any 'special' characters used by regexp, you must escape those characters within m[3] in the custom selector:
如果您的任何自动完成建议包含正则表达式使用的任何“特殊”字符,您必须在自定义选择器中的 m[3] 内转义这些字符:
function escape_regexp(text) {
return text.replace(/[-[\]{}()*+?.,\^$|#\s]/g, "\$&");
}
and change the custom selector:
并更改自定义选择器:
$.expr[':'].textEquals = function (a, i, m) {
return $(a).text().match("^" + escape_regexp(m[3]) + "$");
};
回答by Anonymous
I used something as simple as this for mustMatch and it works. I hope it helps someone.
我为 mustMatch 使用了像这样简单的东西,它可以工作。我希望它可以帮助某人。
change: function (event, ui) {
if (!ui.item) {
$(this).val('');
}
}
回答by Esteban Feldman
I think I got the mustMatch working with this code... It needs thorough test though:
我想我得到了 mustMatch 使用这段代码......不过它需要彻底的测试:
<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>
回答by GordonB
I found this question to be useful.
我发现这个问题很有用。
I thought I'd post up the code I'm now using (adapted from Esteban Feldman's answer).
我想我会发布我现在使用的代码(改编自Esteban Feldman 的回答)。
I've added my own mustMatch option, and a CSS class to highlight the issue before resetting the textbox value.
我已经添加了我自己的 mustMatch 选项和一个 CSS 类来在重置文本框值之前突出显示问题。
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
CSS
.ui-autocomplete-nomatch { background: white url('../Images/AutocompleteError.gif') right center no-repeat; }
回答by varelse
The solution I've used to implement 'mustMatch':
我用来实现“mustMatch”的解决方案:
<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>
回答by CyberJunkie
I discovered one issue. While the suggestion list is active you can submit your form even if the value doesn't match the suggestion. To dissallow this I added:
我发现了一个问题。当建议列表处于活动状态时,即使值与建议不匹配,您也可以提交表单。为了禁止这一点,我补充说:
$('form').submit(function() {
if ($(".ui-autocomplete li:textEquals('" + $(this).val() + "')").size() == 0) {
$(this).val('');
$("span").text("Select a valid city").show();
return false;
}
});
This prevents the form from being submitted and displays a message.
这可以防止表单被提交并显示一条消息。
回答by Bryan Larsen
This JQuery-UI official demo has mustMatch, amongst other cool stuff: http://jqueryui.com/demos/autocomplete/#combobox
这个 JQuery-UI 官方演示有 mustMatch,以及其他很酷的东西:http: //jqueryui.com/demos/autocomplete/#combobox
I've updated it to add autoFill, and a few other things.
我已经更新它以添加自动填充和其他一些东西。
Javascript:
Javascript:
/* stolen from http://jqueryui.com/demos/autocomplete/#combobox * * and these options added. * * - autoFill (default: true): select first value rather than clearing if there's a match * * - clearButton (default: true): add a "clear" button * * - adjustWidth (default: true): if true, will set the autocomplete width the same as * the old select. (requires jQuery 1.4.4 to work on IE8) * * - uiStyle (default: false): if true, will add classes so that the autocomplete input * takes a jQuery-UI style */ (function( $ ) { $.widget( "ui.combobox", { options: { autoFill: true, clearButton: true, adjustWidth: true, uiStyle: false, selected: 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( value ) .autocomplete({ delay: 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) ) ) return { label: text.replace( new RegExp( "(?![^&;]+;)(?!]*)(" + $.ui.autocomplete.escapeRegex(request.term) + ")(?![^]*>)(?![^&;]+;)", "gi" ), "" ), value: text, option: this }; }); found = resp.length > 0; response( resp ); }, select: function( event, ui ) { ui.item.option.selected = true; self._trigger( "selected", event, { item: ui.item.option }); }, change: function( event, ui ) { if ( !ui.item ) { var matcher = new RegExp( "^" + $.ui.autocomplete.escapeRegex( $(this).val() ) + "$", "i" ), valid = false; select.children( "option" ).each(function() { if ( $( this ).text().match( matcher ) ) { this.selected = valid = true; return false; } }); if ( !valid || input.data("autocomplete").term=="" ) { // set to first suggestion, unless blank or autoFill is turned off var suggestion; if(!self.options.autoFill || input.data("autocomplete").term=="") found=false; if(found) { suggestion = jQuery(input.data("autocomplete").widget()).find("li:first")[0]; var option = select.find("option[text="+suggestion.innerText+"]").attr('selected', true); $(this).val(suggestion.innerText); input.data("autocomplete").term = suggestion.innerText; self._trigger( "selected", event, { item: option[0] }); } else { suggestion={innerText: ''}; select.find("option:selected").removeAttr("selected"); $(this).val(''); input.data( "autocomplete" ).term = ''; self._trigger( "selected", event, { item: null }); } return found; } } } }); 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 ) { return $( "" ) .data( "item.autocomplete", item ) .append( "" + item.label + "" ) .appendTo( ul ); }; this.button = $( " " ) .attr( "tabIndex", -1 ) .attr( "title", "Show All Items" ) .insertAfter( input ) .button({ icons: { primary: "ui-icon-triangle-1-s" }, text: false }) .removeClass( "ui-corner-all" ) .addClass( "ui-corner-right ui-button-icon" ) .click(function() { // close if already visible if ( input.autocomplete( "widget" ).is( ":visible" ) ) { input.autocomplete( "close" ); return; } // work around a bug (likely same cause as #5265) $( this ).blur(); // pass empty string as value to search for, displaying all results input.autocomplete( "search", "" ); input.focus(); }); if( self.options.clearButton ) { this.clear_button = $( " " ) .attr( "tabIndex", -1 ) .attr( "title", "Clear Entry" ) .insertAfter( input ) .button({ icons: { primary: "ui-icon-close" }, text: false }) .removeClass( "ui-corner-all" ) .click(function(event, ui) { select.find("option:selected").removeAttr("selected"); input.val( "" ); input.data( "autocomplete" ).term = ""; self._trigger( "selected", event, { item: null }); // work around a bug (likely same cause as #5265) $( this ).blur(); }); } }, destroy: function() { this.input.remove(); this.button.remove(); this.element.show(); $.Widget.prototype.destroy.call( this ); } }); })( jQuery );
CSS (.hjq-combobox is a wrapping span)
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;}
Note: this code is being updated and maintained here: https://github.com/tablatom/hobo/blob/master/hobo_jquery_ui/vendor/assets/javascripts/combobox.js
注意:此代码正在此处更新和维护:https: //github.com/tablatom/hobo/blob/master/hobo_jquery_ui/vendor/assets/javascripts/combobox.js
回答by Randy Cleary
Maybe it's just because this is an old issue, but I found that the easiest solution is already there in the plugin, you just need to use the proper functions to access it.
也许只是因为这是一个老问题,但我发现插件中已经有了最简单的解决方案,您只需要使用适当的功能来访问它。
This code will handle the cases when the autocomplete loses focus with an invalid value:
此代码将处理自动完成因无效值而失去焦点的情况:
change: function(e, ui) {
if (!ui.item) {
$(this).val("");
}
}
And this code, much like the original functionality from bassistance, will handle the cases when there are no matches while typing in the autocomplete:
这段代码,很像 bassistance 的原始功能,将处理在输入自动完成时没有匹配项的情况:
response: function(e, ui) {
if (ui.content.length == 0) {
$(this).val("");
}
}
This works well with either a static array source, or a JSON data source. Combined with the autoFocus: true
option, it seems to do everything needed in an efficient manner.
这适用于静态数组源或 JSON 数据源。结合autoFocus: true
选项,它似乎以有效的方式完成所需的一切。
The last case that you may want to handle is what to do when the ESCAPE key is pressed with an invalid value in the textbox. What I do is use the value of the first matched result. And this is how I do that...
您可能想要处理的最后一种情况是当 ESCAPE 键被按下并且文本框中的值无效时该怎么办。我所做的是使用第一个匹配结果的值。这就是我这样做的方式......
First, declare a variable to hold the best match. Do this outside of your autocomplete plugin.
首先,声明一个变量来保存最佳匹配。在自动完成插件之外执行此操作。
var bestMatch = "";
Then use the following option:
然后使用以下选项:
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();
}
});
}
Lastly, add the following event to your autocomplete:
最后,将以下事件添加到您的自动完成:
.on("keydown", function(e) {
if (e.keyCode == 27) // ESCAPE key
{
$(this).val(bestMatch);
}
})
You can just as easily force the field to be empty when the escape key is pressed. All you have to do is set the value to an empty string when the key is pressed instead of the bestMatch
variable (which isn't needed at all if you choose to empty the field).
当按下退出键时,您可以轻松地将字段强制为空。您所要做的就是在按下键时将值设置为空字符串而不是bestMatch
变量(如果您选择清空字段,则根本不需要)。
回答by Tim Vermaelen
Based on the accepted answer:
基于接受的答案:
My additional requirements: multiple autocompletes, unobtrusive error 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);
}
回答by RishikeshD
Late reply but might help someone!
回复晚了,但可能会帮助某人!
Considering the two events in autocomplete widget
考虑自动完成小部件中的两个事件
1) change - triggered when field is blurred and value is changed.
1) change - 当字段模糊并且值改变时触发。
2) response - triggered when the search completes and the menu is shown.
2) 响应 - 当搜索完成并显示菜单时触发。
Modify the change and response events as follows:
修改变更和响应事件如下:
change : function(event,ui)
{
if(!ui.item){
$("selector").val("");
}
},
response : function(event,ui){
if(ui.content.length==0){
$("selector").val("");
}
}
Hope this helps!
希望这可以帮助!