JQuery UI автозаполнение combobox кнопка click event

Я испытываю странное поведение с jquery ui autocomplete при использовании его для создания combobox. Всякий раз, когда я нажимаю на полосу прокрутки, чтобы прокручивать список результатов, а затем нажмите на мою кнопку со списком, чтобы закрыть результаты, список результатов закрывается, а затем открывается снова. Я ожидаю, что он закроет меню.

Шаги к Repro

  • открыть демонстрационную версию jsfiddle
  • Введите "i" в автозаполнение ИЛИ нажмите кнопку выпадающего списка.
  • Нажмите вертикальную прокрутку для прокрутки результатов
  • Нажмите кнопку выпадающего меню

Script Создать кнопку

 this.button = $("<button type='button'>&nbsp;</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;
}

Мое решение может закрывать виджет, даже если фокус передается самому виджету, а не элементу ввода?

Любые идеи о том, как изменить этот код, чтобы он работал таким образом?

Ответы

Ответ 1

Основываясь на проблемах с различными событиями click и mouse для виджета automplete, я придумал следующее: пример 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'>&nbsp;</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();
});​

Ответ 2

Проблема связана с работой в jquery ui autocomplete. В некоторых случаях для закрытия меню предусмотрена функция mousedown. В одном из условий он проверяет, является ли элемент, который поднял mousedown, частью виджета автозаполнения. Если нет, он закрывает меню. Так как вы используете поведение combobox, и ваша кнопка не является частью виджета автозаполнения, щелчок по кнопке закрывает меню из-за этого события.

Вы можете увидеть оскорбительное условие с тем, почему оно начинается с строки 205 в автозаполнении источника на github. Вероятно, стоит обратить внимание на jquery ui, так как их демо-версия combobox тоже имеет эту ошибку.

UPDATE

Это событие замены основано на jquery-ui 1.8.18. Это событие изменилось и, скорее всего, изменится снова. Возможно, вам придется обновить этот код вручную с каждой версией, если вы пройдете этот маршрут.

Вы можете исправить событие mousedown, чтобы не закрывать меню, если была нажата ваша комбо-кнопка, выполнив следующее после создания своего автозаполнения (jsfiddle demo).

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 внутри кнопки), имеет класс ui-combo-trigger.

Код для создания вашей кнопки относительно не изменился. Нам просто нужно добавить новый класс ui-combo-trigger.

var button = $("<button type='button'>&nbsp;</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();
    });

Ответ 3

Попробуйте 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'>&nbsp;</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();
});

Ответ 4

Брайан объяснил проблему очень хорошо. С помощью 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/#combobox