web-dev-qa-db-fra.com

Select2 ouvrir le menu déroulant sur le focus

J'ai un formulaire avec plusieurs entrées de texte et certains éléments select2. Utiliser le clavier pour passer d’un champ à l’autre fonctionne bien - l’élément Select2 se comporte comme un élément de formulaire et reçoit le focus lorsqu’il est tabulé .

Voici ce que j'ai essayé jusqu'à présent:

$("#myid").select2().on('select2-focus', function(){
     $(this).select2('open');
});

Mais l'utilisation de ce code fait que le menu déroulant s'ouvre à nouveau après la sélection. 

22
andreivictor

L’un des problèmes est qu’une fois ouvert, le tab key ferme le menu déroulant select2 et recentre le widget, ce qui permet de configurer une boucle infinie lors de la tentative d'ouverture du menu déroulant sur tous les événements de focus .

Select 2 Focus

Une astuce consiste à rechercher les différences entre les types d’événements de focus et à ouvrir le menu déroulant uniquement si nous avons un événement de focus béni du navigateur - par opposition à celui généré par jQuery en regardant l’événement original.

Nous pouvons donc modifier le code d'origine de rain01 comme ceci:

$(document).on('focus', '.select2', function (e) {
  if (e.originalEvent) {
    $(this).siblings('select').select2('open');    
  } 
});

Démo de travail dans jsFiddle & Stack Snippets:

$('.select2-nosearch').select2({
  minimumResultsForSearch: 20
});

$(document).on('focus', '.select2', function (e) {
  if (e.originalEvent) {
    $(this).siblings('select').select2('open');    
  } 
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/css/select2.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.0/js/select2.js"></script>

<div class="form-control">
  <label for="foods2" >Select2</label>
  <select id="foods2" class="select2-nosearch" >
    <option value="1">Apple</option>
    <option value="2">Banana</option>
    <option value="3">Carrot</option>
    <option value="4">Donut</option>
  </select>
</div>

Testé sur Chrome, FF, Edge, IE11

14
KyleMit

J'ai essayé les deux réponses de @ irvin-dominin-aka-edward, mais j'ai également rencontré les deux problèmes (avoir à cliquer deux fois sur la liste déroulante, et le fait que Firefox lève l'événement ne soit pas défini).

J'ai trouvé une solution qui semble résoudre les deux problèmes et qui n'a pas encore rencontré d'autre problème. Ceci est basé sur les réponses de @ irvin-dominin-aka-edward en modifiant la fonction select2Focus afin qu'au lieu d'exécuter immédiatement le reste du code, enveloppez-le dans setTimeout.

Code:

function select2Focus() {
    var select2 = $(this).data('select2');
    setTimeout(function() {
        if (!select2.opened()) {
            select2.open();
        }
    }, 0);  
}

Vous pouvez voir une démo ici: http://jsfiddle.net/mtLUp/156/

26
tonywchen

Quelque chose de facile qui fonctionnerait sur toutes les instances select2 de la page.

$(document).on('focus', '.select2', function() {
    $(this).siblings('select').select2('open');
});

UPDATE: Le code ci-dessus ne semble pas fonctionner correctement sur IE11/Select2 4.0.3

PS: ajout d’un filtre pour sélectionner uniquement les champs single. Sélectionner avec multiple l'attribut n'en a pas besoin et casserait probablement s'il était appliqué.

var select2_open;
// open select2 dropdown on focus
$(document).on('focus', '.select2-selection--single', function(e) {
    select2_open = $(this).parent().parent().siblings('select');
    select2_open.select2('open');
});

// fix for ie11
if (/rv:11.0/i.test(navigator.userAgent)) {
    $(document).on('blur', '.select2-search__field', function (e) {
        select2_open.select2('close');
    });
}
20
rain01

Une fois la sélection effectuée, un événement select2-focus est probablement déclenché.

Le seul moyen que j'ai trouvé est une combinaison des événements select2-focus et select2-blur et du gestionnaire jQuery one /.

Ainsi, la première fois que l'élément obtient le focus, select2 est ouvert pour une fois (à cause d'une), lorsque l'élément est flou, le gestionnaire d'événement one est attaché à nouveau, etc.

Code:

$('#test').select2({
    data: [{
        id: 0,
        text: "enhancement"
    }, {
        id: 1,
        text: "bug"
    }, {
        id: 2,
        text: "duplicate"
    }, {
        id: 3,
        text: "invalid"
    }, {
        id: 4,
        text: "wontfix"
    }],
    width: "300px"
}).one('select2-focus', select2Focus).on("select2-blur", function () {
    $(this).one('select2-focus', select2Focus)
})

function select2Focus() {
    $(this).select2('open');
}

Démo: http://jsfiddle.net/IrvinDominin/fnjNb/

METTRE À JOUR

Pour que le clic de la souris fonctionne, vous devez vérifier l'événement qui déclenche le gestionnaire, il doit déclencher la méthode open uniquement si l'événement est focus.

Code:

function select2Focus() {
    if (/^focus/.test(event.type)) {
        $(this).select2('open');
    }
}

Démo: http://jsfiddle.net/IrvinDominin/fnjNb/4/

MISE À JOUR POUR SELECT2 V 4.0

select2 v 4.0 a modifié ses API et abandonné les événements personnalisés (voir https://github.com/select2/select2/issues/1908 ). Il est donc nécessaire de changer la façon de détecter la mise au point.

Code:

$('.js-select').select2({
    placeholder: "Select",
    width: "100%"
})

$('.js-select').next('.select2').find('.select2-selection').one('focus', select2Focus).on('blur', function () {
    $(this).one('focus', select2Focus)
})

function select2Focus() {
    $(this).closest('.select2').prev('select').select2('open');
}

Démo: http://jsfiddle.net/IrvinDominin/xfmgte70/

16
Irvin Dominin

un peu en retard ... mais pour partager mon code avec select2 4.0.0

$("#my_id").select2();
$("#my_id").next(".select2").find(".select2-selection").focus(function() {
    $("#my_id").select2("open");
});
9
Claudio Ikeda

Voici une solution alternative pour la version 4.x de Select2. Vous pouvez utiliser des écouteurs pour capturer l'événement de focus, puis ouvrez la sélection.

$('#test').select2({
    // Initialisation here
}).data('select2').listeners['*'].Push(function(name, target) { 
    if(name == 'focus') {
        $(this.$element).select2("open");
    }
});

Trouvez l'exemple de travail ici basé l'exampel créé par @tonywchen 

6

Le problème est que l'événement de focus interne n'est pas transformé en événement jQuery. J'ai donc modifié le plug-in et ajouté l'événement de focus à EventRelay à la ligne 2063 de Select2 4.0.3: 

EventRelay.prototype.bind = function (decorated, container, $container) {
    var self = this;
    var relayEvents = [
      'open', 'opening',
      'close', 'closing',
      'select', 'selecting',
      'unselect', 'unselecting',
      'focus'
    ];

Ensuite, il suffit d'ouvrir le select2 lorsque le focus se produit:

$('#select2').on('select2:focus', function(evt){
    $(this).select2('open');
});

Fonctionne bien sur Chrome 54, IE 11, 49 FF, Opera 40

4
Tomas Molnar

La réponse de KyleMit a fonctionné pour moi (merci!), Mais j'ai remarqué qu'avec select2 les éléments permettant la recherche, essayer de passer à l'élément suivant ne fonctionnait pas (l'ordre de tabulation était effectivement perdu), j'ai donc ajouté du code pour rétablir le focus à l'élément principal select2 lors de la fermeture du menu déroulant:

$(document).on('focus', '.select2', function (e) {
            if (e.originalEvent) {
                var s2element = $(this).siblings('select');
                s2element.select2('open');
                // Set focus back to select2 element on closing.
                s2element.on('select2:closing', function (e) {
                    s2element.select2('focus');
                });
            }
        });
3
Douglas

Pour moi, en utilisant Select2.full.js Version 4.0.3, aucune des solutions ci-dessus ne fonctionnait comme il se doit… .. J'ai donc écrit une combinaison des solutions ci-dessus… .. Tout d'abord j'ai modifié Select2.full. js de transférer le focus interne et le flou d’événements aux évènements jQuery comme le faisait "Thomas Molnar" dans sa réponse.

EventRelay.prototype.bind = function (decorated, container, $container) {
    var self = this;
    var relayEvents = [
      'open', 'opening',
      'close', 'closing',
      'select', 'selecting',
      'unselect', 'unselecting',
      'focus', 'blur'
    ];

Et puis j'ai ajouté le code suivant pour gérer la mise au point et le flou et la focalisation de l'élément suivant

$("#myId").select2(   ...   ).one("select2:focus", select2Focus).on("select2:blur", function ()
{
    var select2 = $(this).data('select2');
    if (select2.isOpen() == false)
    {
        $(this).one("select2:focus", select2Focus);
    }
}).on("select2:close", function ()
{
    setTimeout(function ()
    {
        // Find the next element and set focus on it.
        $(":focus").closest("tr").next("tr").find("select:visible,input:visible").focus();            
    }, 0);
});
function select2Focus()
{
    var select2 = $(this).data('select2');
    setTimeout(function() {
        if (!select2.isOpen()) {
            select2.open();
        }
    }, 0);  
}
3
Markus1980Wien

J'ai essayé un certain nombre d'entre eux et finalement j'ai trouvé le suivant qui fonctionne pour moi avec Select2 4.0.1. élément est l'élément <select>.

$.data(element).select2.on("focus", function (e) {
    $(element).select2("open");
});
3
EricksonG

J'ai eu le problème qui était à deux volets:
1. Dans un formulaire comportant plusieurs éléments select2, la liste déroulante ne s'ouvrira pas sous l'onglet et vous devez appuyer sur la touche espace pour l'ouvrir.
2. Une fois la sélection effectuée, le tabindex ne sera pas honoré et vous devrez cliquer manuellement sur le champ de saisie suivant. 

Bien que les suggestions habituelles aient fonctionné, j’ai créé ma propre version, puisqu’un script de bibliothèque effectuait la conversion de normal select à select2 et que je n’avais donc aucun contrôle sur cette initialisation. 

Voici le code qui a fonctionné pour moi.

Onglet pour ouvrir  

$(document).on("focus", ".select2", function() {
    $(this).siblings("select").select2("open");
});

Aller à suivant dans la sélection  

var inputs = $("input,select"); // You can use other elements such as textarea, button etc. 
                                //depending on input field types you have used
$("select").on("select2:close",function(){
    var pos = $(inputs).index(this) + 1;
    var next = $(inputs).eq(pos);
    setTimeout( function() {
        next.focus();
        if (next.siblings(".select2").length) { //If it's a select
            next.select2("open");
        }
    }, 500); //The delay is required to allow default events to occur
});

J'espère que cela t'aides.

1
Gaurav

D'une manière ou d'une autre, select2Focus n'a pas fonctionné ici avec une sélection vide, il n'a pas pu comprendre le problème. J'ai donc ajouté le contrôle manuel lorsque l'activation de l'ouverture automatique de l'événement de focus est déclenchée.

Voici coffeescript:

$("#myid").select2()
  .on 'select2-blur', ->
    $(this).data('select2-auto-open', 'true')
  .on 'select2-focus', ->
    $(this).data('select2').open() if $(this).data('select2-auto-open') != 'false'
  .on 'select2-selecting', ->
    $(this).data('select2-auto-open', 'false')
0
Priit

Cela a fonctionné pour moi avec Select2 v4.0.3

//Initialize Select2
 jQuery('.js-select').select2();

// Make Select2 respect tab focus
function select2Focus(){
    jQuery(window).keyup(function (e) {
        var code = (e.keyCode ? e.keyCode : e.which);
        if (code == 9 && jQuery('.select2-search__field:focus').length) {
            jQuery('.js-select').select2('open');
        }
    });
}

select2Focus();

Fork de la démo d'Irvin Dominin: http://jsfiddle.net/163cwdrw/

0
Mark Salvadore

J'ai essayé une solution assez laide mais cela a résolu mon problème.

    var tabPressed = false;

    $(document).keydown(function (e) {
        // Listening tab button.
        if (e.which == 9) {
            tabPressed = true;
        }
    });

    $(document).on('focus', '.select2', function() {
        if (tabPressed) {
            tabPressed = false;
            $(this).siblings('select').select2('open');
        }
    });
0
wmwmwm

J'ai essayé ces solutions avec la version 3.4.8 de select2 et j'ai constaté que lorsque vous faites blur, la select2 se déclenche en premier select2-close, puis select2-focus et ensuite select2-blur, de sorte que nous finissons par rouvrir définitivement le select2.

Ensuite, ma solution est celle-ci:

$('#elemId').on('select2-focus', function(){
    var select2 = $(this).data('select2');
    if( $(this).data('select2-closed') ){
        $(this).data('select2-closed', false)
        return
    }
    if (!select2.opened()) {
        select2.open()
    }
}).on('select2-close', function(){
    $(this).data('select2-closed', true)
})
0
Davsket

une chose importante est de garder le multisélection ouvert tout le temps. Le moyen le plus simple est de déclencher un événement ouvert selon des "conditions" dans votre code:

<select data-placeholder="Choose a Country..." multiple class="select2-select" id="myList">
    <option value="United States">United States</option>
    <option value="United Kingdom">United Kingdom</option>
    <option value="Afghanistan">Afghanistan</option>
    <option value="Aland Islands">Aland Islands</option>
    <option value="Albania">Albania</option>
    <option value="Algeria">Algeria</option>
</select>

javascript:

$(".select2-select").select2({closeOnSelect:false});
$("#myList").select2("open");

violon: http://jsfiddle.net/xpvt214o/153442/

0
rajeev