Empêcher les options jQuery autocomplete de se fermer après chaque sélection

j'utilise Jquery UI autocomplete pour plusieurs valeurs sélectionnables. Tout est bon sauf la liste des options ferme après chaque sélection. Je voudrais que les options restent ouvertes jusqu'à ce que l'utilisateur décide qu'ils ont fait des sélections. J'ai examiné la documentation et je ne vois aucun moyen de garder les options ouvertes. Des idées?

<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>
Tag langages de programmation:
10
demandé sur Rusty 2010-10-13 19:09:37

13 réponses

Vous pouvez faire quelque chose comme ceci: définissez d'abord une variable nommée readyToClose et il faut le false au début. Et quand vous voulez fermer votre menu sur la sélection suivante, définissez cette variable à la true. Et nous devrions aussi réimposer le close méthode de jQuery UI.

ici j'ai réimplémenté le close méthode de jQuery UI dans votre code, pas dans le fichier source! C'est la même chose que nous faisons pour rendre la liste de manière personnalisée (par ex. 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;    
};

Note: dans les versions plus récentes de jQuery (i.e. 1.9.0), remplacer "autocomplete" par "uiAutocomplete", comme dans:

$("#tags")
    .autocomplete({...})
    .data("uiAutocomplete").close = ...
7
répondu Mehran 2013-06-06 21:04:35

je sais que c'est une vieille question qui ne sont plus pertinents pour l'OP, mais par souci d'exhaustivité, une solution plus propre serait d' extend le widget de saisie semi-automatique et prioritaire _close, ainsi que extending de l'objet d'événement dans le select gestionnaire d'événement. Cela vous permet d'effectuer une logique personnalisée pour déterminer si le menu doit être fermé ou non au cas par cas (cas par cas). Voir aussi http://learn.jquery.com/jquery-ui/widget-factory/extending-widgets/

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

au-dessus jQuery.étendre(événement.originalEvent, {keepOpen: true}); est utilisé pour ajouter un keepOpen propriété event.originalEvent. Depuis extend modifie l'objet original( premier argument), toute utilisation ultérieure du même event.originalEvent cette propriété disponible. Après avoir lu et traversai le code, il finit par être le même objet qui est référencé par event dans _close méthode. Ce code se cassera si ce changement devait se produire à l'avenir, mais il est beaucoup plus simple à maintenir que l'équivalent de ce que ingredient_15939 a suggéré il y a 18 mois.

4
répondu user3482702 2014-03-31 20:26:15

l'équipe de jQuery UI pense que c'est une mauvaise pratique UX: http://forum.jquery.com/topic/enhanced-autocomplete-interest-in-getting-this-into-jqueryui#14737000001125152

donc pas de manière intégrée pour l'annuler. Vous pouvez essayer de relancer l'autocomplete après les événements select & close. Et probablement vous devriez mettre en cache le tableau de résultats de sorte qu'aucune nouvelle requête ne soit faite (si C'est en mode Ajax).

N'est pas entré dans les détails cependant - j'ai convaincu mon UI designer que nous n'avons pas besoin de cela pour cette version :)

3
répondu Steponas Dauginis 2010-10-29 10:21:15

j'avais besoin de cette même capacité. IMO les auteurs auraient pu facilement nous donner l'option. Ce que j'ai fait, c'est exclure autocomplete du paquet D'UI, et inclure une copie éditée du fichier séparé: jquery.ui.autocomplete.js (l'obtenir à partir du "développement-bundle\ui" dossier).

j'ai ajouté quelques nouvelles options,closeOnSelect et updateElement (les deux booléens par défaut true), comme suit (en haut du fichier):

$.widget("ui.autocomplete", {
  options: {

  ...

  closeOnSelect: true, // add this line - controls list closing.
  updateElement: true  // add this line - controls updating input box.
},

alors cherchez la chaîne":" dans le code (il n'y seront une seule occurrence). Dans cette fonction, remplacez ces dernières lignes:

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;

Avec ceci:

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.
}

puis Rechercher string"focus: la fonction" (encore une fois, une seule occurrence). Dans cette fonction, remplacer la ligne:

self.element.val(item.value);

Avec ceci:

if (self.options.updateElement) self.element.val(item.value);

maintenant, quand vous créez l'autocomplete, mettez simplement ces deux options comme vous voulez:

$("#txtsearch").autocomplete({
  closeOnSelect: false, // Keep list open when item selected.
  updateElement: false, // Don't change the input box contents.
  // etc...

Cela fonctionne parfaitement pour moi. Indépendamment de que ce soit jugé "mauvaise pratique D'UI" par les auteurs originaux, les besoins de chacun sont différents et les options devraient être là! :)

3
répondu ingredient_15939 2012-09-07 13:20:24

vous aurez besoin d'éditer votre fichier javascript jquery-ui. Dans la section autocomplete, remplacer

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

alors vous devriez être en mesure d'annuler l'événement de fermeture tel que décrit dans la réponse de Shaans.

1
répondu Simon 2011-03-14 13:33:26

Pas si bonne solution, mais j'ai réussi de cette façon:

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;
        }
    }
};
1
répondu Lauri 2012-12-19 14:48:30

Cette solution a fonctionné pour moi. J'utilisais Autocomplete pour afficher une liste des quatre premières possibilités de caractères pour les noms. Puis si l'utilisateur sélectionne l'un de ceux-ci, alors j'ai Autocomplete afficher les noms associés à la sélection. Le menu déroulant autocomplete reste ouvert après la première sélection et vous pouvez voir la liste changer pour les autres options. Espérons que cela aide avec ce fil.

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
    }

}
1
répondu Dunn 2015-01-16 02:43:30

vous pouvez gérer l'événement de fermeture automatique http://jqueryui.com/demos/autocomplete/#multiple

exemples de codes

fournir une fonction de rappel pour gérer l'événement de fermeture comme une option init.

$( ".selector" ).autocomplete({
   close: function(event, ui) { ... }
});

Lier à la clôture de l'événement par type: autocompleteclose.

$( ".selector" ).bind( "autocompleteclose", function(event, ui) {
  ...
});
0
répondu shaans 2010-10-13 15:14:30

sélectionner: function(event,ui)

if (event.keyCode == 13) {
    document.getElementById("#idofautocomplete").value = document.getElementById("#idofautocomplete").value;
 } else if (event.keyCode == 27) {
        $("#idofautocomplete").autocomplete("close");                                                                                   }

fermer: function(event,ui)

document.getElementById("idofautocomplete").value = "";

ça a l'air idiot mais ça marche pour moi. l'utilisateur recherche des articles, sélectionne l'article avec la touche enter, autocomplete est toujours ouvert, l'utilisateur peut sélectionner plus d'options, à tout moment l'utilisateur peut appuyer sur le bouton ESC, fermer autocomplete, la fonction de fermeture efface le texte de autocomplete. je reçois toutes mes informations à partir d'une base de données

0
répondu B Nasty 2011-03-11 07:12:32

j'ai modifié la solution de jQuery UI pour répondre à l'événement de fermeture et ré-ouvrir le menu autocomplete si l'input a toujours la mise au point, l'escape n'a pas été pressée pour fermer le popup, et la valeur de l'input se termine en a', 'ou a' (espace):

close: function(e) {
  if ($el.is(':focus') && e.keyCode !== $.ui.keyCode.ESCAPE && (this.value != null) && /[,\s]+$/.test(this.value)) {
    return $el.autocomplete('search', '');
  }
}

solution complète est ci-dessous:

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', '');
});
0
répondu ralfthewise 2012-10-16 02:55:28

Rapide, seulement css et un peu de hacky solution est la suivante:

...
close: function() {
   $('.ui-menu').css('display', 'block'); //or using #ui-id-x where x is number of autocomplete
}
...
0
répondu Tukkan 2014-07-02 12:38:26

je sais qu'il y a tellement de réponses déjà là, mais je fais quand même référence à une réponse qui est plus claire et directe. Jetez un oeil à cette réponse

Utilisez le même code à partir de la réponse qui gardera ouvert le menu et maintenant afin de cacher le menu de l'extérieur cliquez(sur le corps) puis utilisez le morceau de code ci-dessous.

 $('body').on('click', function(e){
            // click event will prevent for the input and for auto complete menu div
            if($(e.target).hasClass('ui-autocomplete-input') || $(e.target).hasClass('ui-menu-item-wrapper')){
                e.preventDefault();
                return;
            }
// in other case hide the menu
            $("ul.ui-autocomplete").hide();
        });
0
répondu dom 2017-07-13 08:21:37

je sais que c'est une vieille Question , Mais qu'il est encore utile,

ci-dessous est la solution pour la version la plus récente de jquery UI.

$.ui.autocomplete.prototype._close = function(e){
        return false;    
};

OP peut modifier ce code selon ses besoins.

0
répondu chhameed 2017-12-06 06:48:52