web-dev-qa-db-fra.com

jQuery UI Complétion automatique désactiver les événements de sélection et de fermeture

J'utilise l'auto-complétion de l'interface utilisateur de jQuery de manière légèrement différente de celle pour laquelle elle a probablement été créée.

En gros, je souhaite conserver les mêmes fonctionnalités. La seule différence est que lorsque la boîte de suggestion apparaît, je ne sélectionne pas la boîte de suggestion à masquer lorsqu'un utilisateur effectue une sélection et je ne souhaite pas non plus que cette sélection remplisse la zone de saisie. .autocomplete est attaché à.

Alors, j’ai lu la documentation de jQuery UI et il semble y avoir un moyen de désactiver les événements Select: and Close:, mais j’ai trouvé que la façon dont ils l’ont expliqué est très déroutante et c’est pourquoi je suis ici pour demander de l'aide.

Mon 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;   
    }
});

Documentation officielle de l'interface utilisateur jQuery

Déclenché lorsqu'un élément est sélectionné dans le menu; ui.item fait référence à l'élément sélectionné. L'action par défaut de select consiste à remplacer la valeur du champ de texte par la valeur de l'élément sélectionné . L'annulation de cet événement empêche la mise à jour de la valeur, mais pas N'empêche le menu de se fermer.

Exemples de code

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) {
  ...
});

Confusion

Ce qui me trouble, c'est qu'ils semblent suggérer de supprimer le fichier .autocomplete et de le remplacer par .bind ("autocompleteselect") - ce qui désactivera complètement le processus de saisie semi-automatique.

Merci beaucoup pour toute aide que vous pouvez donner.

16
thathurtabit

La deuxième syntaxe utilisant .bind() est simplement un autre moyen de lier un gestionnaire d'événements aux événements personnalisés de jQueryUI. Cela revient exactement à définir le gestionnaire d'événements à l'intérieur des options du widget (en utilisant select: function(event, ui) { })

Imaginez si vous aviez plusieurs widgets de saisie semi-automatique sur la page et que vous vouliez exécuter la même fonction lorsque l'un d'entre eux soulevait l'événement "select", par exemple:

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

Quant à l’annulation de l’événement select, c’est correct. Cependant, l'annulation de l'événement close est un peu plus difficile. il semble que le retour de false à partir du gestionnaire d'événements ne fonctionnera pas (close est déclenché après la fermeture du menu). Vous pouvez effectuer un peu de hackery et remplacer simplement la fonction select par votre propre:

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();
};

Voici un exemple de travail de cela: http://jsfiddle.net/ZGmyp/

Je ne sais pas trop quelles sont les conséquences de l'annulation de l'événement rapproché, mais il ne semble pas que rien de fou se passe dans l'exemple simple. Je dirais que c'est une sorte d'utilisation non naturelle du widget, donc il peut y avoir des conséquences inattendues.

12
Andrew Whitaker

En m'inspirant de la solution Andrews, j'ai trouvé un moyen de garder la saisie semi-automatique ouverte lors de la sélection avec un impact moindre sur les fonctionnalités principales:

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;
    };
})();

L’idée est donc de neutraliser la méthode de fermeture le cas échéant, comme indiqué par le drapeau sélectionné. Avoir sélectionné flag dans un espace de noms global n'est probablement pas la meilleure idée, mais c'est à quelqu'un d'autre d'améliorer :-).

Plus d'informations sur les méthodes prioritaires

19
corolla

J'ai essayé les différentes idées que d'autres ont présentées ici sans succès.

J'utilise Jquery 2.1.4 avec l'interface utilisateur 1.11.4 et voici comment j'ai obtenu que cela fonctionne:

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>

Source Backend "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;

?>
2
Drew

Je suis passé par un chemin légèrement différent pour cela et développé sur Andrew's violon

L’objectif étant que j’ai toujours voulu que l’auto-complétion apparaisse alors qu’une certaine entrée avait le focus, ce qui permettait de multiples sélections.

$("#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", "")
});
1
Davie Brown

Aller avec $ input.data ("autocomplete"). Menu.options.selected = function () {} Empêchait de conserver la valeur après la sélection d'un autre élément (notre implémentation devait être ajoutée à la fin. Peut-être simplement nécessaire ajoutez e.preventDefault () ou renvoyez false avant d'ajouter le code). Donc, je viens juste de changer dans l’événement close. Exemple de mettre une variable externe et d’écrire sa propre méthode, c’est mieux, mais je n’ai pas aimé. J'ai d'abord pensé à appeler la méthode manuellement en transmettant un paramètre lorsqu'il est nécessaire de fermer autocomplte à la main. (Dans notre implémentation, le client demandait que la liste soit ouverte lorsque l'on clique sur les éléments, mais fermée lorsque la souris quitte le conteneur de la zone de texte. 

Je viens donc de joindre la saisie semi-automatique au conteneur d’éléments de textbox, ainsi que mouseenter et mouseleave. Pour déterminer s'il doit se fermer, j'ai utilisé la variable personnalisée jQuery (this) .data ("canClose"). Fondamentalement, cela ne fait que rouvrir la saisie semi-automatique avec la méthode de recherche lorsque variable est 'false'.

Voici le code final:

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");
            });

si vous devez effectuer l’ajout au lieu de la valeur de remplacement, ajoutez le gestionnaire de sélection dans le constructeur:

 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;
                }
0
Andrey Doloka