Автозаполнение пользовательского интерфейса jQuery отключить события выбора и закрытия

Я использую автозаполнение jQuery UI несколько иначе, чем оно, вероятно, было создано для этого.

В основном я хочу сохранить все те же функции, с той лишь разницей, что, когда появляется окно предложений, я не скрываю окно предложений, когда пользователь делает выбор, и я также не хочу, чтобы этот выбор заполнял поле ввода. который прикреплен к .autocomplete.

Итак, я прочитал документацию jQuery UI, и, похоже, есть способ отключить события Select: и Close :, но я считаю, что способ, которым они объяснили это, очень запутанный, и, следовательно, вот почему я Я прошу о помощи.

Мой jQuery

$( "#comment" ).autocomplete({
    source: "comments.php",
    minLength: 4,

    // Attempt to remove click/select functionality - may be a better way to do this        
    select: function( event, ui ) {
        return false;
    },
    // Attempt to add custom Class to the open Suggestion box - may be a better way
    open : function (event, ui) {
        $(this).addClass("suggestion-box");
    },
    // Attempt to cancel the Close event, so when someone makes a selection, the box does not close
    close : function (event, ui) {
        return false;   
    }
});

Официальная документация jQuery UI

Срабатывает при выборе элемента в меню; ui.item относится к выбранному элементу. По умолчанию действие select - заменить значение текстового поля значением выбранного элемента. Отмена этого события предотвращает обновление значения, но не предотвращает закрытие меню.

Примеры кода

Supply a callback function to handle the select event as an init option.
$( ".selector" ).autocomplete({
   select: function(event, ui) { ... }
});
Bind to the select event by type: autocompleteselect.
$( ".selector" ).bind( "autocompleteselect", function(event, ui) {
  ...
});

Путаница

Что меня смущает, так это то, что они, кажется, предлагают удалить .autocomplete и заменить его на .bind ("autocompleteselect"), что полностью отключит автозаполнение?

Большое спасибо за любую помощь, которую вы можете оказать.


person thathurtabit    schedule 18.05.2011    source источник


Ответы (5)


Второй синтаксис с использованием .bind() - это просто еще один способ присоединения обработчика событий к пользовательским событиям jQueryUI. Это точно так же, как определение обработчика событий внутри параметров виджета (с использованием select: function(event, ui) { })

Представьте, что у вас есть несколько виджетов автозаполнения на странице, и вы хотите выполнить ту же функцию, когда любой из них вызывает событие «select», например:

$(".autocomplete").bind("autocompleteselect", function(event, ui) {
    /* Will occur when any element with an autocomplete widget fires the
     * autocomplete select event.
     */
});

Что касается отмены события select, это у вас правильно. Однако отменить событие close немного сложнее; похоже, что возврат false из обработчика событий не сработает (close запускается после закрытия меню). Вы можете немного взломать и просто заменить функцию select своей собственной:

var $input = $("input").autocomplete({
    source: ['Hello', 'Goodbye', 'Foo', 'Bar']
});
$input.data("autocomplete").menu.options.selected = function(event, ui) { 
    var item = ui.item.data( "item.autocomplete" );
    $input.focus();
};

Вот рабочий пример этого: http://jsfiddle.net/ZGmyp/

Я не уверен, каковы последствия переопределения события закрытия, но не похоже, что в простом примере происходит что-то сумасшедшее. Я бы сказал, что это неестественное использование виджета, поэтому могут быть неожиданные последствия.

person Andrew Whitaker    schedule 18.05.2011
comment
Большое спасибо за это @Andrew, можете ли вы придумать способ отменить функцию Click / select, но все же изменить поле предложения при изменении ввода и / или когда пользователь отменяет выбор поля ввода? - person thathurtabit; 18.05.2011
comment
@thathurtabit: меню должно обновляться по мере того, как вы вводите предложения. Что вы имеете в виду, когда меняете поле предложений, когда выбор ввода отменен? - person Andrew Whitaker; 18.05.2011
comment
@AndrewWhitaker Спасибо, что связались со мной, да, я ищу, чтобы меню все еще обновлялось, когда вводятся предложения. Я только что попробовал вашу демонстрацию еще раз, и она обновляется, если вы вводите другое предложение, которое оно распознает, но если вы вводите кого-то совершенно другого (и он не распознает), он по-прежнему сохраняет свое предыдущее несоответствующее предложение. Кроме того, когда вы щелкаете за пределами поля ввода (чтобы избавиться от его фокуса), окно предложений остается открытым. - person thathurtabit; 18.05.2011
comment
@thathurtabit: Понятно - посмотрю еще раз - person Andrew Whitaker; 18.05.2011
comment
Спасибо, Андрей, очень признателен за вашу помощь! - person thathurtabit; 18.05.2011
comment
@thathurtabit: Это может занять немного больше времени, чем я думал изначально. Я продолжу изучать это! - person Andrew Whitaker; 18.05.2011
comment
@thathurtabit: Попробуйте самый последний код из моего ответа. Это начинает казаться более хакерским, но должно работать. - person Andrew Whitaker; 18.05.2011
comment
@ Эндрю Уитакер, похоже, это отлично работает! Ты легенда! Большое спасибо за вашу помощь, сэр. - person thathurtabit; 18.05.2011
comment
@thathurtabit: Нет проблем! Рад помочь. - person Andrew Whitaker; 18.05.2011

Вдохновленный решением Эндрюса, я нашел способ оставить автозаполнение открытым при выборе с меньшим влиянием на основные функции:

var selected;  //flag indicating a selection has taken place

var $input = $("input").autocomplete({
    source: ['Hello', 'Goodbye', 'Foo', 'Bar'],
    select: function( event, ui ) {
        selected = true;
    }
});

//Override close method - see link below for details
(function(){
   var originalCloseMethod = $input.data("autocomplete").close;
    $input.data("autocomplete").close = function(event) {
        if (!selected){
            //close requested by someone else, let it pass
            originalCloseMethod.apply( this, arguments );
        }
        selected = false;
    };
})();

Таким образом, идея состоит в том, чтобы стерилизовать метод закрытия, когда это необходимо, как указано выбранным флагом. Выбор флага в глобальном пространстве имен, вероятно, не лучшая идея, но это может улучшить кто-то другой :-).

Подробнее о методах переопределения

person corolla    schedule 02.07.2011
comment
Потрясающе, это очень помогло мне - person wesbos; 09.12.2011
comment
Отличная идея переопределить встроенные методы. Спасибо. - person BasTaller; 12.06.2012
comment
+1, помогло ваше решение. И очень часто бывает полезно исправить таким образом методы jQuery UI (и подобных виджетов). - person raina77ow; 04.09.2013
comment
Работает отлично. Но в 2019 году (для актуальных версий jQuery) вам нужно использовать $input.data("uiAutocomplete") вместо $input.data("autocomplete"), чтобы он работал. - person Alex; 20.12.2019

Я безуспешно пробовал различные идеи, представленные здесь другими.

Я использую JQuery 2.1.4 с UI 1.11.4, и вот как у меня это работает:

Javascript:


<script>
var lookup_selectable = false;
var lookup_term = '';

$(function() {

    $( "#lookup" ).autocomplete({
        source: "lookup_processor.php",
        minLength: 3,
        renderItem: function( ul, item ) {

            // This function is called for each item returned from the 'source:'
            // It is up to you to ensure that a list item element is returned.

            // do whatever logic on the item data to determine if it should not be slectable..


            //Example:
            // The backend "source" has handled the logic of what is selectable or not
            // and has set a 'selectable' parameter that we can use
            if(item.selectable){                  
                // return the item unchanged from autocompletes default behavior
                return $("<li></li>").data("item.autocomplete", item).append("<a>" + item.label + "</a>").appendTo(ul);              
            }else{
                // this item is not selectable so lets apply a class named 'item-disabled' to give a visual queue. 
                // We are also wrapping the label in a span instead of an anchor just to show that the item is still clickable,  darn!
                return $('<li class="ui-menu-item item-disabled"></li>').data("item.autocomplete", item).append('<span>'+item.label+'</span>').appendTo(ul);                  
            }

        },

        select: function( event, ui ) {                                  

            // This item was clicked ..

            // save the item.clickable value to our own external variable
            // Note: We have to do this because the item object is not available in the 'close' function :-(
            lookup_selectable = ui.item.selectable;  // the item object is available inside the ui parameter

            // store the current search term
            lookup_term = $('#lookup').val();

            // do any additional stuff based on the item selected, if needed...


        },

        close: function(event, ui){

            // This function fires after select: and after autocomplete has already "closed" everything.  This is why event.preventDefault() won't work.               
            // ** ui is an empty object here so we have to use our own variable to check if the selected item is "selectable" or not..                              
            if (! lookup_selectable){
                // We need to undo what autocomplete has already done..                                                       
                $('#lookup').val(lookup_term); // Restore the search term value
                $('#'+event.currentTarget.id).show(); // Keep the selection window open
                // ta-da!  To the end user, nothing changes when clicking on an item that was not selectable.
            }    
        }

    });
});
</script>  

CSS:


<style>
li.ui-menu-item.item-disabled {
    text-decoration: none;    
    line-height: 1.5;    
    color: #ccc;
}
</style>

Внутренний источник "lookup_processor.php":


<?php

        $search_results = array();

    // ..do whatever to get the data for each item
    $item_data = getting_item_data();

    foreach ($item_data as $data){
        // The id, label, and value keys are the typical keys that autocomplete expects,  but you can add ass many others as you want..
        // For our example we are setting the 'selectable' key to true or false based on some simple example logic
        $search_results[] = array(
            'id'=>$data['id'], 
            'label'=>$data['label'], 
            'value'=>$data['value'], 
            'selectable'=>$data['some_thing_to_check']>0?true:false, // This is the parameter our 'select:' function is looking for
            'send_it_all_if_you_want'=>json_encode($data)); // this is just an example of how you can send back anything you want 
         );
     }

    // send the results back to autocomplete
    echo json_encode($search_results);
    exit;

?>
person Drew    schedule 22.03.2016

Я пошел по другому пути и расширил скрипку Эндрю.

Цель заключалась в том, что я всегда хотел, чтобы автозаполнение отображалось, пока определенный ввод был в фокусе, что позволяло несколько вариантов выбора.

$("#myInput").autocomplete({
    source: ["Test", "This", "Doesnt", "Close"],
    minLength: 0,
    select: function (event, ui) {
        // Add your own custom login to manipulate ui.item.label and add what you need the input field (and ui.item.value if required.)
        // We've customised how we want the select to "work" so prevent the default
        // of auto clearing the input.    
        event.preventDefault();
    },
    close : function(event)
    {
        // We're closing the autocomplete - check if the input still has focus...
        if ($("#myInput").is(":focus"))
        {
            // Prevent the auto complete from closing.
            event.preventDefault();

            // Make sure we're reshowing the autcomplete - since the input would have momentarily
            // lost focus when we selected an item.
            $("#myInput").autocomplete("search", "")
        }        
    }
});

$("#myInput").focus(function () {
    // We're not taking any filtering into account for this example.
    $(this).autocomplete("search", "")
});
person Davie Brown    schedule 14.04.2015
comment
Это действительно помогло мне создать динамический многоуровневый выбор, что мне нужно, так это то, что если вы выберете определенный элемент, вы получите новый список элементов. Я потратил часы на то, чтобы понять это. Все используют простые варианты, но не демонстрируйте эту функцию. очень скоро напишу страницу для этой функции. - person PBo; 14.10.2017

Переход с $ input.data ("autocomplete"). Menu.options.selected = function () {} привел к тому, что значение не сохранялось после выбора другого элемента (нашу реализацию нужно было добавить в конец. Возможно, нужно было просто добавить e.preventDefault ( ) или верните false перед добавлением кода). Так что я просто переключился на событие закрытия. пример с постановкой внешней переменной и написанием собственного метода лучше, но тоже не понравился. Сначала я вызываю метод вручную с передачей параметра, когда нужно закрыть автозаполнение вручную. (в нашей реализации заказчик требовал, чтобы список открывался при щелчке по элементам, но закрывался, когда мышь покидает контейнер текстового поля.

Поэтому я просто прикрепил автозаполнение к контейнеру элемента текстового поля и прикрепил mouseenter и mouseleave. Чтобы определить, следует ли закрывать, я использовал пользовательскую переменную jQuery (this) .data ("canClose"). По сути, он просто повторно открывает автозаполнение с помощью метода поиска, когда переменная имеет значение false.

Вот окончательный код:

element.autocomplete({
                minLength:0,
                source: source,
                appendTo: element.parent(),
                close: function () {
                    if (!jQuery(this).data("canClose")) {
                        jQuery(this).autocomplete('search', '');
                    }
                    return false;
                }
            });
            element.mouseenter(function () {
                element.data("canClose", false);
                jQuery(this).autocomplete('search', '');
            });
            element.parent().mouseleave(function () {
                element.data("canClose", true);
                element.delay(2000).autocomplete("close");
            });

если вам нужно выполнить добавление вместо значения замены, добавьте обработчик выбора в конструктор:

 select: function (event, ui) {
                    var text = element.text().trim();
                    if (text.length > 0 && !text.endsWith(",")) {
                        text += ", ";
                    }
                    jQuery(this).text((text + ui.item.label));
                    jQuery(this).focus();
                    return false;
                }
person Andrey Doloka    schedule 05.12.2016