web-dev-qa-db-fra.com

événement de clavier dans la liste déroulante

J'essaie de créer une liste déroulante, qui lorsqu'un utilisateur détient la touche MAJ, il sélectionnera le même index sur toutes les autres listes déroulantes.

Actuellement, je fais ce qui suit:

$(document).on('keyup keydown', function (e) { shifted = e.shiftKey });
$(document).on('change', '.report_info select', function (e) {
    if (shifted) {
        //Code to change other drop down lists.
    }
});

Cela ne fonctionne que si vous maintenez la touche Maj enfoncée avant d'entrer dans la liste déroulante. Si vous êtes dans la DDL et que vous appuyez sur la touche Maj, l'événement keyup/keydown ne se déclenchera pas et shifted restera false

Y a-t-il un moyen d'attraper l'événement keyup/keydown lorsqu'une liste déroulante est ciblée?

Modifier:

On dirait que cela pourrait être un problème avec Chrome seulement, juste essayé d'ajouter ce qui suit, et cela fonctionne dans Firefox et IE, mais pas Chrome:

$(document).on('keyup keydown', 'select', function (e) {
    shifted = e.shiftKey;
});

Voici un violon qui ne fonctionne pas en chrome: http://jsfiddle.net/ue6xqm1q/4

18
Bryan

Je pense que la réponse de @ judgeja pourrait être votre meilleur pari. Je publie ceci sous la forme d'une "réponse" au lieu d'un commentaire, car j'ai effectué mes propres recherches pour déterminer qu'aucun événement n'est déclenché lorsqu'un élément select est ouvert dans Chrome.

Voir Fiddle: http://jsfiddle.net/m4tndtu4/6/

J'ai attaché tous les gestionnaires d'événements possibles (je pense) à l'élément input et aux deux éléments select.

Dans Chrome, de nombreux événements sont déclenchés lorsque vous utilisez l'élément input, mais aucun événement ne se déclenche lorsque vous utilisez le premier élément select lorsqu'il est ouvert.

Il est intéressant de noter que les événements do / sont déclenchés dans Chrome si l’élément select a l’attribut multiple ou size> 1.

Dans Firefox, vous verrez des événements se déclencher sur les trois éléments.

En dehors de la suggestion de @ judgeja, votre meilleur choix peut être de simuler l'élément select.

9
Rick Hitchcock

UPDATE

Avertissement: le (mauvais) comportement de Chrome diffère d'une plate-forme à l'autre! Sous Windows, un événement de raccourci est déclenché juste après la publication de la sélection, ce qui n'est pas le cas sous OsX. Ceci explique pourquoi la solution @judgeja a fonctionné pour certains et n'a pas Pour moi, alors que le mien travaillait sur OsX et non pas sur Windows.

J'ai donc créé un violon mis à jour pour fusionner ma solution OsX avec celle de Windows.

http://jsfiddle.net/0fz5vcq6/5/

Sur les plates-formes où le keydown est déclenché, la solution @judgeja est testée. Si elle n'est pas déclenchée, elle teste un événement keyup sans la précédente keydown (ma solution précédente). Il est moche car il ne fonctionne qu’après la relâchement de la touche Maj, mais moche uniquement sur Chrome OsX.

var shifted = false;
var hackytimer = 0;
var lastval=null;

$(document).keydown(function(e){
    if(e.which == 16){
        if(Date.now() - hackytimer <200){
            alert("you pressed shift inside the select (Win)");
           changeAllSelects($(this).val());
       }        shifted = true;
    }
});

$(document).keyup(function(e){
    if(e.which == 16) {
        if(!shifted && lastval!=null) {

            alert("you pressed shift inside the select (OsX)");
            $('.report_info select').each(function () {
                changeAllSelects(lastval);
            });

        }
        shifted = false;
    }
});

$(document).on('change', '.report_info select', function (e) {
    hackytimer = Date.now();        
    if (shifted) {
        changeAllSelects($(this).val());
    } else {
        lastval=$(this).val();
    }
});

function changeAllSelects(cr){
    hackytimer = 0;
    $('.report_info select').each(function () {
        $(this).val(cr);
    });
}

Le mérite revient principalement à @judgeja pour sa solution de minuterie avec une solution de contournement supplémentaire pour le Mac (et d'autres plates-formes qui se comportent de la même manière).

Je pense toujours qu'émuler les sélections avec quelque chose de HTML comme http://gregfranko.com/jquery.selectBoxIt.js/ est plus propre car elles ne doivent pas interférer avec keydown/keyups.

SOLUTION PRÉCÉDENTE (OsX uniquement)

La seule solution à laquelle je pouvais penser, en l'absence totale de tout événement, est de vérifier si une montée en puissance s'est produite sans la descente précédente. Cela peut fonctionner si vous n'avez pas d'autres éléments qui se comportent de la même manière que les sélections.

http://jsfiddle.net/6jkkgx5e/

C'est un peu délicat et sale, cela fonctionnera APRÈS que l'utilisateur relâche la touche Maj

var shifted = false;
var lastval=null;

$(document).keydown(function(e){
    if(e.which == 16){
        shifted = true;
    }
});

$(document).keyup(function(e){
    if(e.which == 16){
        if(!shifted && lastval!=null) {

            alert("you pressed shift inside the select");
            $('.report_info select').each(function () {
                $(this).val(lastval);
            });

        }
        shifted = false;
    }
});

$(document).on('change', '.report_info select', function (e) {
    var cr = $(this).val();
    if (shifted) {
        $('.report_info select').each(function () {
            $(this).val(cr);
        });
    } else {
        lastval=cr;
    }
});

Devrait se comporter normalement sur des navigateurs non bogués. Quoi qu'il en soit, je suis d'accord pour émuler les sélections avec quelque chose de HTML comme http://gregfranko.com/jquery.selectBoxIt.js/ pourrait être le moyen le plus propre.

5
FrancescoMM

Pour être honnête, il s’agit là d’une solution assez astucieuse, mais c’est un moyen de parvenir à une fin en attendant de trouver quelque chose de mieux.

Comme le problème est chrome, n'enregistre les événements keydown/keyup sur les éléments select qu'après la disparition de la liste déroulante, nous devons soit: 

a) comprendre comment faire en sorte que l'événement se déclenche (je n'en ai aucune idée) 

ou 

b) vérifie si nos conditions ont été remplies dans un ordre différent. 

Chrome déclenchera l'événement touche après chaque clic afin que nous puissions simplement vérifier si vous avez appuyé sur click immédiatement avant cet événement. Etant donné que les autres navigateurs se comportent mieux, nous allons également laisser le code précédent en place.

Pour ce faire, nous définissons un timer sur l'événement click, puis lorsque l'événement shift de la sélection est déclenché, si le timer de l'événement click vient également d'être défini, nous devrions exécuter notre code ici pour que chrome le déclenche. Nous réinitialisons alors le chronomètre pour qu'il ne soit pas déclenché plusieurs fois.

NOTE: si vous appuyez sur Shift immédiatement après avoir défini les valeurs (dans la limite du clic que vous avez spécifié), toutes les seront également définies. Je ne pense pas que ce soit déraisonnable, car cela semble tout à fait naturel quand cela se produit.

J'ai utilisé le code suivant:

var shifted = false;
var hackytimer = 0;

$(document).on('keyup keydown', function (e) { 
    shifted = e.shiftKey;
});

$(document).on('keyup keydown', 'select', function (e) {
    shifted = e.shiftKey;
    if(Date.now() - hackytimer <200){
        changeAllSelects($(this).val());
    }
});

$(document).on('change', '.report_info select', function (e) {
    hackytimer = Date.now();        
    if (shifted) {
        changeAllSelects($(this).val());
    }
});

function changeAllSelects(cr){
    hackytimer = 0;
    $('.report_info select').each(function () {
        $(this).val(cr);
    });
}

Voir exemple de travail ici: http://jsfiddle.net/0fz5vcq6/2/

3
James

Bryan, Vous pouvez essayer la méthode suivante. J'ai testé sur Jsfiddle ça marche à votre façon Si j'ai bien compris votre question.

 var shifted = false;
$(document).on('keyup keydown', function (e) { shifted = e.shiftKey; });

$("select").on('keyup keydown',  function (e) {
    shifted = e.shiftKey;  
});
    $('.report_info select').on('change',  function (e) {
        var cr = $(this).val();
        if (shifted) {
            $('.report_info select').each(function () {
                $(this).val(cr);
            });
        }
    });

S'il vous plaît laissez-moi savoir si cela fonctionne pour vous.

1
Vinod Kumar

Bonjour cela ne fonctionnait pas parce que vous ne vous concentrez pas sur votre sélection

essaye ça

http://jsfiddle.net/t8fsuy33/

$('select').first().focus();
1
Prozi

Vérifiez le fonctionnement JS FIDDLER

Essayez le script suivant pour votre scénario

 <script type="text/javascript" language="javascript">
    window.shifted = false;
    $(document).on('keyup keydown', function (e) { shifted = e.shiftKey; });
    $(document).on('change', 'select.report_info', function (e) {
        var cr = $(this).val();
        if (shifted) {
            $('.report_info').each(function () {
                $(this).val(cr);
            });
        }
    });
</script>
1
Mayank

Hop cette chose vous aider .. :)

 var onkeydown = (function (ev) {
      var key;
      var isShift;
      if (window.event) {
        key = window.event.keyCode;
        isShift = window.event.shiftKey ? true : false;
      } else {
        key = ev.which;
        isShift = ev.shiftKey ? true : false;
      }
      if ( isShift ) {
        switch (key) {
          case 16: // ignore shift key
            break;
          default:
            alert(key);
            // do stuff here?
            break;
        }
      }
    });
1
O-mkar

Tout d'abord. Vous devez choisir un événement pour vous inscrire. Ne vous inscrivez pas pour keyup et keydown en même temps. Vous donnez du temps dur au navigateur, car ils affectent votre résultat final. Pour voir ce que je veux dire, modifiez simplement le plunk, ajoutez un événement keyup. Le résultat final se comporte un peu négligé.

keyup : L'événement est déclenché lorsqu'une touche est relâchée sur le clavier.

keydown : Evénement déclenché lorsqu'une touche est enfoncée sur le clavier.

pression du clavier : événement déclenché lorsqu'une touche est enfoncée sur le clavier.

Ils ont leurs différences, mieux vaut s'en tenir à un, je préfère pour cet exemple d'utiliser keydown, joue simplement mieux avec moi, vous pouvez utiliser keyup.

Edit : Une note rapide. Le keyup de mon exemple ne joue pas bien, car il semble que le changement dans le selectedIndex, vient en premier et ensuite l'événement lié. Lors du raccourci clavier, l’événement est déclenché puis fonctionne, puis l’indice selectedIndex est modifié. Pour jouer avec keyup, le code ci-dessous nécessite quelques modifications, ce qui signifie que l'étape n'est pas nécessaire lorsque vous utilisez keyup.

J'ai une démo de plnkr ici

Je l'ai testé sur IE10, Opera, Safari, Firefox et Chrome. Comme vous vous en doutez, les navigateurs Webkit, ne déclenchez pas l'événement keydown/keyup/keypress lorsqu'une liste de sélection est active. Raison inconnue pour moi, pour le moment. Dans Firefox fonctionne très bien. On IE fonctionne partiellement. Alors, pour atteindre votre objectif, personnalisez le code à la rescousse! Je viens de lier un événement de changement au document, j’entends parler de changement et de changement. Si le type d'événement est modifié, la solution de contournement entre en jeu. Voici du code:

$(document).ready(function(){
    $(document).on('keydown change', 'select', function(evt){
        var shiftKey = evt.shiftKey;
        var code = evt.keyCode || evt.which;

        //if it's a change event and i dont have any shiftKey or code
        //set the to a default value of true
        if(evt.type === 'change' && !shiftKey && !code){
          //special! only when change is fired
          shiftKey = true;
          code = true; 
        }

        //if shift key
        if(shiftKey && (code === 40 || code === 38 || code === true)){

          var target = $(evt.target);
          //if code is not true means it is not a change event, go ahead and set
          //a step value, else no step value
          var step = (code !== true) ? (code === 40) ? 1 : -1 : 0;
          var index = target[0].selectedIndex + step;

          //just to keep the lower and upper bound of the select list
          if(index < 0){
            index = 0;
          }else if(index >= target[0].length){
            index = target[0].length - 1;
          }

          //get all other select lists
          var allOtherSelects = target.closest('div').siblings('div').children('select');
          //foreach select list, set its selectedIndex
          $.each(allOtherSelects, function(i, el){
            el.selectedIndex = index;
          });
        }
      });
    });
1
gdyrrahitis

Votre syntaxe semble incorrecte.

$("#target").keydown(function() {
    alert( "Handler for .keydown() called." );
});
1
MCSharp

Chrome hack: vous pouvez définir un événement personnalisé pour le document. Et déclencher cet événement lorsque vous appuyez sur la touche Maj dans la DDL. Le déclencheur de déclenchement JQuery peut transmettre des paramètres personnalisés.

1
Deep

J'ai trouvé une solution unique à ce problème, spécialement pour Chrome. Il semble que Chrome se déplace en dehors du dom normal pour certains éléments lorsqu'ils ont le focus, de sorte que les événements onkey (down | press | up) ne capturent jamais le keycode. Toutefois, si la taille de la zone de sélection est> 1, cela fonctionne. Mais quiconque veut une liste déroulante réelle au lieu de ce qui ressemble à une liste déroulante peut résoudre ce problème avec ce code. Dans mon cas, j’essayais d’empêcher la touche Retour arrière de revenir à la page précédente du navigateur. 

Javascript ressemble à ceci:

      $(document).ready(function() { 
          $('select').keypress(function(event) 
             { return cancelBackspace(event) });
        $('select').keydown(function(event) 
           { return cancelBackspace(event) });
       }); 

      function cancelBackspace(event) {
         if (event.keyCode == 8) {
            return false;
          }
       }

Alors HTML ressemble à ceci:

<select id="coaacct" style="border:none;width:295px;" onclick="if (this.size){this.size=''}else{this.size='20'};">

J'utilise l'événement onclick pour changer la taille de la zone de sélection à 20 si elle n'a pas de taille et la redéfinir à rien si elle a une taille. De cette façon, il fonctionne comme une liste déroulante de sélection normale, mais comme il a une taille supérieure à 1 lorsque vous sélectionnez l’option, il détectera les codes clés. Je n'ai pas vu cette réponse adéquate nulle part ailleurs, alors j'ai pensé partager ma solution.

0
user3520445

Si vous avez besoin de faire des choses avec un menu déroulant qui soit aussi granulaire, cela ne vaut probablement pas la peine d'utiliser l'élément <select> natif tel quel. Dans ce seul fil, de nombreuses différences d’implémentation sont discutées, et bien d’autres dépassent le cadre de la présente discussion, mais vous affecteront probablement également. Plusieurs bibliothèques JS peuvent encapsuler ce contrôle, le laisser tel quel sur un mobile (où le contrôle natif est réellement nécessaire), mais l'émuler sur un ordinateur de bureau, où le contrôle ne fait pas grand chose qui ne peut pas être imité dans JS. .

0
Adam Leggett