我正在使用Jquery UI's autocomplete for multiple selectable values。一切都很好,除了每个选择后选项列表关闭。我希望选项保持开放,直到用户决定完成选择。我查看了文档,但我没有看到任何方法来保持选项的开放性。有什么想法吗?
<meta charset="utf-8">
<script>
$(function() {
var availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C",
"C++",
"Clojure",
"COBOL",
"ColdFusion",
"Erlang",
"Fortran",
"Groovy",
"Haskell",
"Java",
"JavaScript",
"Lisp",
"Perl",
"PHP",
"Python",
"Ruby",
"Scala",
"Scheme"
];
function split( val ) {
return val.split( /,\s*/ );
}
function extractLast( term ) {
return split( term ).pop();
}
$( "#tags" ).autocomplete({
minLength: 0,
source: function( request, response ) {
// delegate back to autocomplete, but extract the last term
response( $.ui.autocomplete.filter(
availableTags, extractLast( request.term ) ) );
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function( event, ui ) {
var terms = split( this.value );
// remove the current input
terms.pop();
// add the selected item
terms.push( ui.item.value );
// add placeholder to get the comma-and-space at the end
terms.push( "" );
this.value = terms.join( ", " );
return false;
}
});
});
</script>
标签编程语言:
答案 0 :(得分:8)
您可以这样做:
首先定义一个名为readyToClose
的变量,并在开头将其设置为false
。如果要在下次选择时关闭菜单,请将此变量设置为true
。我们还应该重新实现JQuery UI的close
方法。
这里我在代码中重新实现了JQuery UI的close
方法,而不是在源文件中!这与我们以自定义方式呈现列表的方式相同(例如http://jqueryui.com/demos/autocomplete/custom-data.html)
var readyToClose = false;
$( "#tags" ).autocomplete({
minLength: 0,
source: function( request, response ) {
// delegate back to autocomplete, but extract the last term
response( $.ui.autocomplete.filter(
availableTags, extractLast( request.term ) ) );
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function( event, ui ) {
var terms = split( this.value );
// remove the current input
terms.pop();
// add the selected item
terms.push( ui.item.value );
// add placeholder to get the comma-and-space at the end
terms.push( "" );
this.value = terms.join( ", " );
return false;
}
}).data( "autocomplete" ).close = function(e){
if(readyToClose)
clearTimeout(this.closing), this.menu.element.is(":visible") && (this.menu.element.hide(), this.menu.deactivate(), this._trigger("close", e));
else
return false;
};
注意:在较新版本的jQuery(即1.9.0)中,将“autocomplete”替换为“uiAutocomplete”,如:
$("#tags")
.autocomplete({...})
.data("uiAutocomplete").close = ...
答案 1 :(得分:4)
我知道这是一个旧问题,可能不再与OP相关,但为了完整起见,更清晰的解决方案是extend
自动完成窗口小部件并覆盖{{1} },以及_close
extend
事件处理程序中的事件对象。这允许您执行自定义逻辑以确定是否应根据具体情况(逐个事件)关闭菜单。另请参阅http://learn.jquery.com/jquery-ui/widget-factory/extending-widgets/
select
在上面的 jQuery.extend(event.originalEvent,{keepOpen:true})中,用于向//override the autocomplete widget
jQuery.widget( "ui.autocomplete", jQuery.ui.autocomplete, {
_close: function( event ) {
if(event!== undefined && event.keepOpen===true) {
//trigger new search with current value
this.search( null, event );
return true;
}
//otherwise invoke the original
return this._super( event );
}
});
$('ac').autocomplete(
{
...custom options...
select: function( event, ui ) {
...custom logic...
if(menu should remain open) {
//extend original event with special flag to keep dropdown open
//the o-event continues to be passed through the chain of listeners
//and will end up being processed during _close()
jQuery.extend(event.originalEvent,{keepOpen:true});
//modify value as required
jQuery(this).val(...);
return false; //prevent selected value from being set,
//i.e. keeping modified value above
}
}
}
);
添加特殊的keepOpen
属性。由于event.originalEvent
修改了原始对象(第一个参数),因此对同一extend
的任何后续使用都将具有此属性。阅读并逐步执行代码后,它最终成为event.originalEvent
方法中event
引用的同一对象。
如果将来这种情况发生变化,这段代码将会中断,但是,维护起来要比18个月前的ingredient_15939建议更容易。
答案 2 :(得分:3)
jQuery UI团队认为这是不良的用户体验:http://forum.jquery.com/topic/enhanced-autocomplete-interest-in-getting-this-into-jqueryui#14737000001125152
所以没有内置的取消方式。您可以尝试在选择&amp; amp;近距离事件。也许您应该缓存结果数组,以便不会发出新请求(如果它处于Ajax模式)。
虽然没有深入了解细节 - 我已经说服我的UI设计师在这个版本中我们不需要这个:)
答案 3 :(得分:3)
我需要同样的能力。 IMO作者可以很容易地给我们选择。我所做的是从UI包中排除自动完成,并包含单独文件的编辑副本:jquery.ui.autocomplete.js
(从“development-bundle \ ui”文件夹中获取)。
我添加了几个新选项closeOnSelect
和updateElement
(两者都是布尔默认值为true),如下所示(位于文件顶部):
$.widget("ui.autocomplete", {
options: {
...
closeOnSelect: true, // add this line - controls list closing.
updateElement: true // add this line - controls updating input box.
},
然后在代码中搜索字符串“ selected:”(只会出现一次)。在此函数中,替换最后几行:
if ( false !== self._trigger( "select", event, { item: item } ) ) {
self.element.val( item.value );
}
// reset the term after the select event
// this allows custom select handling to work properly
self.term = self.element.val();
self.close( event );
self.selectedItem = item;
有了这个:
if (false !== self._trigger("select", event, { item: item })) {
if (self.options.updateElement) {
self.element.val(item.value);
self.term = self.element.val(); // Ensure term string is same.
}
if (self.options.removeOnSelect) { // Remove menu item if option is true.
console.log(ui);
} else {
self.selectedItem = item;
}
if (self.options.closeOnSelect) self.close(event); // Close menu if option is true.
} else { // Returned false.
self.term = self.element.val(); // Ensure term string is same, in case callback changed element value.
}
然后搜索字符串“焦点:功能”(再次,只出现一次)。在该函数中,替换行:
self.element.val(item.value);
有了这个:
if (self.options.updateElement) self.element.val(item.value);
现在,当您创建自动填充时,只需根据需要设置这两个选项:
$("#txtsearch").autocomplete({
closeOnSelect: false, // Keep list open when item selected.
updateElement: false, // Don't change the input box contents.
// etc...
这对我来说很有效。无论原作者是否认为它是“糟糕的UI练习”,每个人的需求都是不同的,选择应该在那里! :)
答案 4 :(得分:1)
您需要编辑jquery-ui javascript文件。在自动填充部分替换
close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this._trigger("close",a);this.menu.element.hide();this.menu.deactivate()}}
与
close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){if(this._trigger("close",a)!==false){this.menu.element.hide();this.menu.deactivate()}}}
然后您应该能够取消关闭事件,如Shaans的回答中所述。
答案 5 :(得分:1)
不是那么好的解决方案,但我像这样管理它:
var $input = $('input').autocomplete({
select: function(event, obj) {
var ac_data = $(event.target).data("autocomplete");
ac_data.instaSearch = true;
// Your action
return false;
}
});
$input.data("autocomplete")._close = function( event ) {
if ( this.menu.element.is( ":visible" )) {
this.menu.element.hide();
this.menu.blur();
this.isNewMenu = true;
this._trigger( "close", event );
if (this.instaSearch) {
this.search(this.term);
this.instaSearch = false;
}
}
};
答案 6 :(得分:1)
这个解决方案对我有用。我正在使用自动填充功能显示名称前四个字符可能性的列表。然后,如果用户选择其中一个,那么我有自动完成显示与选择相关联的名称。第一次选择后,自动完成下拉列表保持打开状态,您可以看到列表更改为其他选项。希望这有助于这个主题。
select: function( event, ui ) {
// the number of chars was driving my decision for behavior, yours may be different
if (chars.length <= 4) {
jq.each(ui, function(key, value) {
jq.each(value, function(key1, value1) {
// put the selected value in the text area,
// since normal behavior will be prevented
jq("#mod_autocomplete").val(value1);
// trigger another search
jq("#mod_autocomplete").autocomplete("search");
// open the autocomplete dropdown
jq("#mod_autocomplete").autocomplete("open");
});
});
event.preventDefault();
} else {
// put whatever behavior you need here for next selection
}
}
答案 7 :(得分:1)
我知道那里已经有很多答案,但我仍然提到一个更干净,更直接的答案。请查看此answer
使用与将保持打开菜单的答案相同的代码,现在为了隐藏菜单的外侧点击(在正文上),然后使用下面的代码。
vendor.bundle.js net::ERR_CONTENT_LENGTH_MISMATCH
bootstrap 195fcde…:54 Uncaught TypeError: Cannot read property 'call' of undefined
at __webpack_require__ (bootstrap 195fcde…:54)
at Object.2 (main.ts:11)
at __webpack_require__ (bootstrap 195fcde…:54)
at webpackJsonpCallback (bootstrap 195fcde…:25)
at main.bundle.js:1
答案 8 :(得分:0)
您可以处理自动填充关闭事件http://jqueryui.com/demos/autocomplete/#multiple
代码示例
提供一个回调函数来处理close事件作为init选项。
$( ".selector" ).autocomplete({
close: function(event, ui) { ... }
});
按类型绑定到关闭事件:autocompleteclose。
$( ".selector" ).bind( "autocompleteclose", function(event, ui) {
...
});
答案 9 :(得分:0)
选择:function(event,ui)
if (event.keyCode == 13) {
document.getElementById("#idofautocomplete").value = document.getElementById("#idofautocomplete").value;
} else if (event.keyCode == 27) {
$("#idofautocomplete").autocomplete("close"); }
close:function(event,ui)
document.getElementById("idofautocomplete").value = "";
看起来很傻但它对我有用。 用户搜索项目,用回车键选择项目,自动完成仍然打开,用户可以选择更多选项,用户可以随时点击ESC按钮,关闭自动完成,关闭功能从自动完成中清除文本。我从数据库中获取所有信息
答案 10 :(得分:0)
我调整了来自JQuery UI的解决方案以响应close事件并重新打开自动完成菜单,如果输入仍然具有焦点,则没有按下转义来关闭弹出窗口,并且输入的值以任一方式结束a','或''(空格):
close: function(e) {
if ($el.is(':focus') && e.keyCode !== $.ui.keyCode.ESCAPE && (this.value != null) && /[,\s]+$/.test(this.value)) {
return $el.autocomplete('search', '');
}
}
完整的解决方案如下:
var $el = $('#autocomplete-field');
$el.bind('keydown', function(e) {
if (e.keyCode === $.ui.keyCode.TAB && $(this).data('autocomplete').menu.active) {
e.preventDefault();
}
}).autocomplete({
delay: 0,
autoFocus: true,
minLength: 0,
source: function(req, resp) {
resp($.ui.autocomplete.filter(source, extractLast(req.term)));
},
focus: function() {
return false;
},
select: function(e, ui) {
var terms;
terms = regexSplit(this.value);
terms.pop();
terms.push(ui.item.value);
terms.push('');
this.value = terms.join(', ');
return false;
},
close: function(e) {
if ($el.is(':focus') && e.keyCode !== $.ui.keyCode.ESCAPE && (this.value != null) && /[,\s]+$/.test(this.value)) {
return $el.autocomplete('search', '');
}
}
}).focus(function() {
$el.autocomplete('search', '');
});
答案 11 :(得分:0)
速度快,只有css和一点hacky解决方案是:
...
close: function() {
$('.ui-menu').css('display', 'block'); //or using #ui-id-x where x is number of autocomplete
}
...
答案 12 :(得分:0)
我知道这是旧问题,但它仍然有用,
以下是 jquery UI 的lattest版本的解决方案。
$.ui.autocomplete.prototype._close = function(e){
return false;
};
OP可以根据需要修改此代码。
答案 13 :(得分:0)
我自己遇到了这个问题。这是一个简单的衬套,适合所有人使用,只需将其放入自动完成选项即可。
$ac.autocomplete({
...
close: function () { $('.ui-autocomplete').show() }
});
如果要关闭它,或者希望它在关闭时淡出,则可以删除close语句,或者分别在末尾添加.fadeOut()
。
$ac.autocomplete({
...
close: function () { $('.ui-autocomplete').show().fadeOut() }
});
答案 14 :(得分:0)
我正在集成一个bootstrap jquery ui项目,并且在这里已经完成了打开和关闭的原则。
$.widget('ui.' + internalComplete, $.ui.autocomplete, {
options: {
cancelClose: function(event, ui) {
return false;
}
},
close: function( event ) {
if (!this._trigger('cancelClose', event, { ui: this.menu.element })) {
this._super( event );
}
}
});
第二步是根据条件选择关闭
this.uiEl = this.element[internalComplete](
{
minLength: 0,
focus: opts.focus,
select: opts.select,
cancelClose: function(event, ui) {
var hasMenuItem = _applyOriginalEvent(event, function(e) {
return $(e.target).hasClass('ui-menu-item') || null;
});
return hasMenuItem === true;
}
}
)[internalComplete]('instance');
答案 15 :(得分:0)
/ ** *由高左于2019/12/25创建。 * /
(function($) {
var internalComplete = 'card-internalAutocomplete';
var _uuid = 0;
function _applyOriginalEvent(event, fn) {
var ret = fn(event);
if (ret == null) {
var oe = event.originalEvent;
if (oe != null) {
return _applyOriginalEvent(oe, fn);
}
}
return ret;
}
$.widget('ui.' + internalComplete, $.ui.autocomplete, {
options: {
cancelClose: function(event, ui) {
return false;
}
},
close: function( event ) {
if (!this._trigger('cancelClose', event, { ui: this.menu.element })) {
this._super( event );
}
}
});
$.widget('ui.card-autocomplete', {
options: {
source: null,
link: ' a.card-link',
/* source: [
{
title: 'title',
subtitle: 'Card subtitle',
desc: 'Some quick example text to build on the card title and make up the bulk of the cards content.',
'group-prefix': 'js',
groups: [
{
value: "sizzlejs",
label: "Sizzle JS",
desc: "a pure-JavaScript CSS selector engine",
icon: "sizzlejs_32x32.png"
}
]
}
],*/
focus: $.noop,
select: function(event, ui) {
return false;
}
},
_create: function() {
var that = this,
opts = this.options;
this.uiEl = this.element[internalComplete](
{
minLength: 0,
focus: opts.focus,
select: opts.select,
cancelClose: function(event, ui) {
var hasMenuItem = _applyOriginalEvent(event, function(e) {
return $(e.target).hasClass('ui-menu-item') || null;
});
return hasMenuItem === true;
}
}
)[internalComplete]('instance');
this._on(this.element, {
focus: function(event) {
this.uiEl.search(null, event);
}
});
$.extend(this.uiEl, {
_renderMenu: function(ui, items) {
$.each(opts.source, function(i, n) {
that._createCards($('<li>').appendTo(ui), n, items);
});
}
});
this.uiEl.menu.option('items', this.options.link);
this._initSource();
},
_initSource: function() {
var data = this.options.source;
if ($.isArray(data)) {
this.setSource(this._dataToSource(data));
}
},
_setOption: function(key, value) {
this._super( key, value );
if ( key = 'source') {
this._initSource();
}
},
setSource: function(array) {
this.uiEl.option('source', array);
},
_dataToSource: function(data) {
var array = [];
var that = this;
$.each(data, function(i, n) {
that._initData(array, n);
});
return array;
},
_initData: function(array, group) {
if ($.isArray(group.groups)) {
var prefix = group.prefix =
( group.prefix || $.ui['card-autocomplete'].getPrefix( true ) );
$.each(group.groups, function(i, n) {
n._prefix = prefix;
array.push(n);
});
delete group.groups;
}
},
_createCards: function(li, n, list) {
var body = $('<div>').addClass('card-body');
li.append( $('<div>').addClass('card').append(body) );
if (n.title != null) {
body.append( $('<h5>').addClass('card-title').text(n.title) );
}
if (n.subtitle != null) {
body.append( $('<h6>').addClass('card-subtitle mb-2 text-muted').text(n.subtitle) );
}
if (n.desc != null) {
body.append( $('<p>').addClass('card-text').text(n.desc) );
}
this._createList(n, list, body);
},
_createList: function(n, list, body) {
var that = this;
$.each(list, function(i, li) {
if (li._prefix == n.prefix) {
that._renderLi(li, body);
}
});
},
_renderLi: function(li, body) {
$.ui['card-autocomplete'].createLi(li)
.appendTo( body )
.data( "ui-autocomplete-item", li );
}
});
$.extend($.ui['card-autocomplete'], {
createLi: function(li) {
var link = $('<a>').addClass('card-link').prop('href', '#').text(li.label);
if (li.desc != null) {
link.prop('title', li.desc)
}
if (li.value != null) {
link.attr('data-id', li.value);
}
return link;
},
getPrefix: function(next) {
if (next) {
_uuid++;
}
return "-" + _uuid;
}
});
})(jQuery);
****************************** html **************** *********************************
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>jQuery UI Autocomplete - Custom data and display</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link rel="stylesheet" href="../../../themes/base/jquery.ui.all.css">
<!--<link rel="stylesheet" href="../../demos.css">-->
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="jquery-ui.js"></script>
<script src="jquery.ui.cards.autocomplete.js"></script>
<!--<script src="../../../ui/jquery.ui.core.js"></script>
<script src="../../../ui/jquery.ui.widget.js"></script>
<script src="../../../ui/jquery.ui.position.js"></script>
<script src="../../../ui/jquery.ui.menu.js"></script>
<script src="../../../ui/jquery.ui.autocomplete.js"></script>-->
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<style>
#project-label {
display: block;
font-weight: bold;
margin-bottom: 1em;
}
#project-icon {
float: left;
height: 32px;
width: 32px;
}
#project-description {
margin: 0;
padding: 0;
}
</style>
<script>
$(function() {
var projects = [
{
title: 'Card title',
subtitle: 'Card subtitle',
desc: 'Some quick example text to build on the card title and make up the bulk of the cards content.',
groups: [
{
value: "jquery",
label: "jQuery",
desc: "the write less, do more, JavaScript library",
icon: "jquery_32x32.png"
},
{
value: "jquery-ui",
label: "jQuery UI",
desc: "the official user interface library for jQuery",
icon: "jqueryui_32x32.png"
}
]
},
{
title: '第二个分组',
subtitle: '第二个分组.....',
desc: '第二个分组的描述....',
groups: [
{
value: "sizzlejs",
label: "Sizzle JS",
desc: "a pure-JavaScript CSS selector engine",
icon: "sizzlejs_32x32.png"
}
]
}
];
var ele = $( "#project" )['card-autocomplete']({
minLength: 0,
source: projects,
focus: function( event, ui ) {
return false;
},
select: function( event, ui ) {
return false;
}
});
});
</script>
</head>
<body>
<div id="project-label">Select a project (type "j" for a start):</div>
<img id="project-icon" src="../images/transparent_1x1.png" class="ui-state-default" alt="">
<input id="project" class="w-50">
<input type="hidden" id="project-id">
<p id="project-description"></p>
<div class="demo-description">
<p>You can use your own custom data formats and displays by simply overriding the default focus and select actions.</p>
<p>Try typing "j" to get a list of projects or just press the down arrow.</p>
</div>
</body>
</html>