JQuery UI автозаполнение комбобокс событие нажатия кнопки
Я испытываю странное поведение с автозаполнением jquery ui при использовании его для создания комбинированного списка. Всякий раз, когда я нажимаю на полосу прокрутки для прокрутки списка результатов И затем нажимаю на кнопку со списком, чтобы закрыть результаты, список результатов закрывается, а затем открывается снова. Я ожидаю, чтобы закрыть меню.
Шаги к репро
- открыть демо jsfiddle
- Введите "я" в автозаполнение ИЛИ нажмите кнопку раскрывающегося списка.
- Нажмите на вертикальную прокрутку, чтобы прокрутить результаты
- Нажмите на кнопку выпадающего
Скрипт для создания кнопки
this.button = $("<button type='button'> </button>")
.attr({ "tabIndex": -1, "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 () {
// when i put breakpoint here, and my focus is not on input,
// then this if steatment is false????
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();
});
CSS (принудительно прокручивать меню длинных результатов)
.ui-autocomplete {
max-height: 100px;
overflow-y: auto;
/* prevent horizontal scrollbar */
overflow-x: hidden;
/* add padding to account for vertical scrollbar */
padding-right: 20px;
}
/* IE 6 doesn't support max-height
* we use height instead, but this forces the menu to always be this tall
*/
* html .ui-autocomplete {
height: 100px;
}
Мое решение может быть закрытие виджета, даже если фокус переносится на сам виджет, а не на элемент ввода?
Любые идеи, как изменить этот код, чтобы он вел себя таким образом?
4 ответа
Основываясь на проблемах с различными событиями щелчка и мыши для виджета автозаполнения, я пришел к следующему: пример jsFiddle.
JQuery:
var input = $('#txtComplete');
var data = [];
var isOpen = false;
function _init() {
for (var idx = 0; idx <= 100; idx++) {
data.push('item: ' + idx);
};
input.autocomplete({
source: data,
minLength: 0,
open: function(event, ui) {
isOpen = true;
},
select: function(event, ui) {
isOpen = false;
}
});
}
function afterInit() {
var button = $("<button type='button'> </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(event) {
input.focus();
if (isOpen) {
input.autocomplete("close");
isOpen = false;
} else {
input.autocomplete("search", "");
event.stopImmediatePropagation();
}
});
}
$(window).click(function() {
input.autocomplete("close");
isOpen = false;
});
$(function() {
_init();
afterInit();
});
Проблема из-за обхода в автозаполнении JQuery UI. Существует настройка события mousedown, чтобы закрыть меню при определенных условиях. В одном из условий он проверяет, является ли элемент, вызвавший mousedown, частью виджета автозаполнения. Если нет, он закрывает меню. Поскольку вы обращаете внимание на поведение выпадающего списка и ваша кнопка не является частью виджета автозаполнения, щелчок по кнопке закрывает меню из-за этого события.
Вы можете увидеть состояние сбоя с указанием причины его появления, начиная со строки 205 в источнике автозаполнения на github. Вероятно, стоит поднять этот вопрос на форумах jquery ui, так как в их демонстрационной версии combobox также есть эта ошибка.
ОБНОВИТЬ
Это событие замещения основано на jquery-ui 1.8.18. Это событие изменилось и, скорее всего, снова изменится. Возможно, вам придется обновить этот код вручную с каждым выпуском, если вы идете по этому пути.
Вы можете исправить mousedown
событие, чтобы не закрывать меню, если была нажата ваша кнопка со списком, выполнив следующую команду после создания автозаполнения ( демонстрация jsfiddle).
var input = $('#combotextbox').autocomplete(/*options*/);
input.data('autocomplete').menu.element.unbind('mousedown').mousedown(function(event) {
var self = input.data('autocomplete');
event.preventDefault();
// clicking on the scrollbar causes focus to shift to the body
// but we can't detect a mouseup or a click immediately afterward
// so we have to track the next mousedown and close the menu if
// the user clicks somewhere outside of the autocomplete
var menuElement = self.menu.element[0];
if (!$(event.target).closest(".ui-menu-item").length) {
setTimeout(function() {
$(document).one('mousedown', function(event) {
var t = $(event.target);
if (event.target !== self.element[0] && event.target !== menuElement && !$.ui.contains(menuElement, event.target) && !t.hasClass('ui-combo-trigger') && !t.parent().hasClass('ui-combo-trigger')) {
self.close();
}
});
}, 1);
}
// use another timeout to make sure the blur-event-handler on the input was already triggered
setTimeout(function() {
clearTimeout(self.closing);
}, 13);
});
Это удаляет текущее событие mousedown, а затем добавляет его обратно с добавленной проверкой, чтобы увидеть, есть ли элемент, вызвавший событие или его родительский элемент (нажатие кнопки или пользовательский значок внутри кнопки) имеет класс ui-combo-trigger
,
Код для создания вашей кнопки относительно не изменился. Нам просто нужно добавить новый класс ui-combo-trigger
,
var button = $("<button type='button'> </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 ui-combo-trigger").click(function(event) {
// when i put breakpoint here, and my focus is not on input,
// then this if steatment is false????
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();
event.stopImmediatePropagation();
});
Попробуйте это jsfiddle. Я думаю, что это поможет вам.
var input = $('#txtComplete');
var data = [];
var openCheck = false;
function _init() {
for (var idx = 0; idx <= 100; idx++) {
data.push('item: ' + idx);
};
input.autocomplete({
source: data,
minLength: 0,
open: function(event, ui) {
openCheck = true;
},
select: function(event, ui) {
openCheck = false;
}
});
}
function afterInit() {
var button = $("<button type='button'> </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(event) {
if (openCheck) {
input.autocomplete("close");
openCheck = false;
} else {
input.autocomplete("search", "");
}
});
}
$(function() {
_init();
afterInit();
});
Брайан объяснил проблему очень хорошо. С помощью jquery ui 11 вы можете сделать что-то вроде:
wasOpen = false;
$button
.mousedown(function() {
wasOpen = input.autocomplete( "widget" ).is( ":visible" );
})
.click(function() {
input.focus();
// Close if already visible
if ( wasOpen ) {
return;
}
см. пример на http://jqueryui.com/autocomplete/