web-dev-qa-db-fra.com

Existe-t-il un événement onSelect ou un équivalent pour HTML <select>?

J'ai un formulaire de saisie qui me permet de choisir parmi plusieurs options et de faire quelque chose lorsque l'utilisateur modifie la sélection. Par exemple,

<select onChange="javascript:doSomething();">
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

Désormais, doSomething() ne se déclenche que lorsque la sélection change .

Je veux déclencher doSomething() lorsque l'utilisateur sélectionne une option, éventuellement la même option .

J'ai essayé d'utiliser un gestionnaire "onClick", mais cela se déclenche avant que l'utilisateur ne lance le processus de sélection.

Alors, y at-il un moyen de déclencher une fonction sur chaque sélection par l'utilisateur?

Mise à jour:

La réponse suggérée par Darryl semblait fonctionner, mais cela ne fonctionnait pas toujours. Parfois, l'événement est déclenché dès que l'utilisateur clique sur le menu déroulant, avant même que l'utilisateur ait terminé le processus de sélection!

190
ePharaoh

Voici le moyen le plus simple:

<select name="ab" onchange="if (this.selectedIndex) doSomething();">
    <option value="-1">--</option>
    <option value="1">option 1</option> 
    <option value="2">option 2</option>
    <option value="3">option 3</option>
</select>

Fonctionne à la fois avec la sélection de la souris et avec les touches haut/bas du clavier lorsque la sélection est sélectionnée.

82
freezethrower

J'avais besoin de quelque chose d'exactement pareil. C'est ce qui a fonctionné pour moi:

<select onchange="doSomething();" onfocus="this.selectedIndex = -1;">
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

Soutient ceci:

lorsque l'utilisateur sélectionne une option, éventuellement la même chose encore

58
Alex

J'ai eu le même problème lorsque je créais un design il y a quelques mois. La solution que j'ai trouvée consistait à utiliser .live("change", function()) en combinaison avec .blur() sur l'élément que vous utilisez.

Si vous souhaitez que quelque chose se passe lorsque l'utilisateur clique simplement, au lieu de changer, il suffit de remplacer change par click.

J'ai attribué à ma liste déroulante un ID, selected, et j'ai utilisé les éléments suivants:

$(function () {
    $("#selected").live("change", function () {

    // do whatever you need to do

    // you want the element to lose focus immediately
    // this is key to get this working.
    $('#selected').blur();
    });
});

J'ai vu que celui-ci n'avait pas de réponse choisie, alors j'ai décidé de donner mon avis. Cela a très bien fonctionné pour moi. J'espère que quelqu'un d'autre pourra utiliser ce code lorsqu'il est bloqué.

http://api.jquery.com/live/

Edit: utilisez le sélecteur on par opposition à .live. Voir jQuery .on ()

11
Cody

Juste une idée, mais est-il possible de mettre un clic sur chacun des éléments <option>?

<select>
  <option onclick="doSomething(this);">A</option>
  <option onclick="doSomething(this);">B</option>
  <option onclick="doSomething(this);">C</option>
</select>

Une autre option pourrait être d'utiliser onblur sur la sélection. Cela se déclenche chaque fois que l'utilisateur clique hors de la sélection. À ce stade, vous pouvez déterminer quelle option a été sélectionnée. Pour que cela se déclenche au bon moment, il suffit de cliquer sur l'une des options pour brouiller le champ (rendre quelque chose d'autre ou simplement .blur () dans jQuery).

8
Darryl Hein

L’approche onclick n’est pas totalement mauvaise, mais comme cela a été dit, elle ne sera pas déclenchée lorsque la valeur ne sera pas modifiée par un clic de souris.
Il est toutefois possible de déclencher l'événement onclick dans l'événement onchange.

<select onchange="{doSomething(...);if(this.options[this.selectedIndex].onclick != null){this.options[this.selectedIndex].onclick(this);}}">
    <option onclick="doSomethingElse(...);" value="A">A</option>
    <option onclick="doSomethingElse(..);" value="B">B</option>
    <option onclick="doSomethingElse(..);" value="Foo">C</option>
</select>
6
user1845327

Je vais développer la réponse de Jitbit. J'ai trouvé cela bizarre lorsque vous avez cliqué sur le menu déroulant, puis que vous avez désactivé le menu déroulant sans rien sélectionner. A fini avec quelque chose comme:

var lastSelectedOption = null;

DDChange = function(Dd) {
  //Blur after change so that clicking again without 
  //losing focus re-triggers onfocus.
  Dd.blur();

  //The rest is whatever you want in the change.
  var tcs = $("span.on_change_times");
  tcs.html(+tcs.html() + 1);
  $("span.selected_index").html(Dd.prop("selectedIndex"));
  return false;
};

DDFocus = function(Dd) {
  lastSelectedOption = Dd.prop("selectedIndex");
  Dd.prop("selectedIndex", -1);

  $("span.selected_index").html(Dd.prop("selectedIndex"));
  return false;
};

//On blur, set it back to the value before they clicked 
//away without selecting an option.
//
//This is what is typically weird for the user since they 
//might click on the dropdown to look at other options,
//realize they didn't what to change anything, and 
//click off the dropdown.
DDBlur = function(Dd) {
  if (Dd.prop("selectedIndex") === -1)
    Dd.prop("selectedIndex", lastSelectedOption);

  $("span.selected_index").html(Dd.prop("selectedIndex"));
  return false;
}; 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<select id="Dd" onchange="DDChange($(this));" onfocus="DDFocus($(this));" onblur="DDBlur($(this));">
  <option>1</option>
  <option>2</option>
</select>
<br/>
<br/>Selected index: <span class="selected_index"></span>
<br/>Times onchange triggered: <span class="on_change_times">0</span>

Cela est un peu plus logique pour l'utilisateur et permet à JavaScript de s'exécuter chaque fois qu'il sélectionne une option, y compris une option antérieure.

L'inconvénient de cette approche est qu'elle supprime la possibilité de passer d'une liste à une autre et d'utiliser les touches de direction pour sélectionner la valeur. C’était acceptable pour moi puisque tous les utilisateurs cliquent sur tout jusqu’à la fin de l’éternité.

5
Tyler Stahlhuth

Si vous en avez vraiment besoin, je le ferais (pour que cela fonctionne avec le clavier et la souris)

  • Ajouter un gestionnaire d'événements onfocus à la sélection pour définir la valeur "actuelle"
  • Ajouter un gestionnaire d'événements onclick à la sélection pour gérer les modifications de la souris
  • Ajouter un gestionnaire d'événements onkeypress à la sélection pour gérer les modifications du clavier

Malheureusement, onclick s'exécutera plusieurs fois (par exemple, à la fermeture de select ... et à la sélection/fermeture) et le onkeypress peut se déclencher si rien ne change ...

<script>
  function setInitial(obj){
    obj._initValue = obj.value;
  }
  function doSomething(obj){
    //if you want to verify a change took place...
    if(obj._initValue == obj.value){
      //do nothing, no actual change occurred...
      //or in your case if you want to make a minor update
      doMinorUpdate();
    } else {
      //change happened
      getNewData(obj.value);
    }
  }
</script>


<select onfocus="setInitial(this);" onclick="doSomething();" onkeypress="doSomething();">
  ...
</select>
4
scunliffe

Pour déclencher correctement un événement chaque fois que l'utilisateur sélectionne quelque chose (même la même option), il vous suffit de tromper la zone de sélection.

Comme d'autres l'ont dit, spécifiez un selectedIndex négatif sur le focus pour forcer l'événement de modification. Bien que cela vous permette de tromper la zone de sélection, cela ne fonctionnera pas après cela tant qu'il aura le focus. La solution simple consiste à forcer le flou dans la zone de sélection, comme indiqué ci-dessous.

Standard JS/HTML:

<select onchange="myCallback();" onfocus="this.selectedIndex=-1;this.blur();">
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

plugin jQuery:

<select>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

<script type="text/javascript">
    $.fn.alwaysChange = function(callback) {
        return this.each(function(){
            var elem = this;
            var $this = $(this);

            $this.change(function(){
                if(callback) callback($this.val());
            }).focus(function(){
                elem.selectedIndex = -1;
                elem.blur();
            });
        });
    }


    $('select').alwaysChange(function(val){
        // Optional change event callback,
        //    shorthand for $('select').alwaysChange().change(function(){});
    });
</script>

Vous pouvez voir un démo de travail ici .

4
Jim Buck

En fait, les événements onclick NE se déclenchent PAS lorsque l'utilisateur utilise le clavier pour modifier la sélection dans le contrôle de sélection. Vous devrez peut-être utiliser onChange et onClick pour obtenir le comportement que vous recherchez.

3

Mon objectif était donc de pouvoir sélectionner plusieurs fois la même valeur, ce qui écrase la fonction onchange () et la transforme en une méthode onclick () utile.

Sur la base des suggestions ci-dessus, je suis arrivé à ce qui fonctionne pour moi.

<select name="ab" id="hi" onchange="if (typeof(this.selectedIndex) != undefined) {alert($('#hi').val()); this.blur();}" onfocus="this.selectedIndex = -1;">
    <option value="-1">--</option>
    <option value="1">option 1</option>
    <option value="2">option 2</option>
    <option value="3">option 3</option>
</select>

http://jsfiddle.net/dR9tH/19/

2
Sean D

Ce que j’ai fait face à un problème similaire, c’est que j’ai ajouté un "onFocus" à la zone de sélection qui ajoutait une nouvelle option générique ("select une option" ou quelque chose de similaire) et l’utilisait par défaut comme option sélectionnée.

2
David Polehonski

Ce qui fonctionne pour moi:

<select id='myID' onchange='doSomething();'>
    <option value='0' selected> Select Option </option>
    <option value='1' onclick='if (!document.getElementById("myID").onchange()) doSomething();' > A </option>
    <option value='2' onclick='if (!document.getElementById("myID").onchange()) doSomething();' > B </option>
</select>

De cette façon, onchange appelle 'doSomething ()' lorsque l'option est modifiée et onclick appelle 'doSomething ()' lorsque l'événement onchange est défini sur false, autrement dit, lorsque vous sélectionnez la même option.

1
antoniobh

Voici ma solution, complètement différente de toute autre solution ici. Il utilise la position de la souris pour déterminer si une option a été sélectionnée, par opposition à un clic sur la case de sélection pour ouvrir la liste déroulante. Il utilise la position event.screenY car il s'agit de la seule variable fiable pour tous les navigateurs. Un événement de survol doit d'abord être associé afin qu'il puisse déterminer la position des contrôles par rapport à l'écran avant l'événement click.

var select = $("select");

var screenDif = 0;
select.bind("hover", function (e) {
    screenDif = e.screenY - e.clientY;
});
select.bind("click", function (e) {
    var element = $(e.target);
    var eventHorizon = screenDif + element.offset().top + element.height() - $(window).scrollTop();
    if (e.screenY > eventHorizon)
        alert("option clicked");
});

Voici mon jsFiddle (http://jsfiddle.net/sU7EV/4/

1
Ally

utilisez jquery:

<select class="target">
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

<script>
    $('.target').change(function() { doSomething(); });
</script>
1
ladookie
<script>
function abc(selectedguy) {
alert(selectedguy);
}
</script>

<select onchange="abc(this.selectedIndex);">
<option>option one</option>
<option>option two</option>
</select>

Vous avez ici l'index renvoyé et, dans le code js, vous pouvez utiliser ce retour avec un commutateur ou tout autre choix.

1
JMFDB

Ce qui est merveilleux avec la balise select (dans ce scénario), c’est qu’elle prendra sa valeur parmi les balises option.

Essayer:

<select onChange="javascript:doSomething(this.value);">
<option value="A">A</option>
<option value="B">B</option>
<option value="Foo">C</option>
</select>

Travaillé convenablement pour moi.

1
Tzshand

Cela peut ne pas répondre directement à votre question, mais ce problème pourrait être résolu par de simples ajustements au niveau de la conception. Je comprends que cela peut ne pas s'appliquer à 100% à tous les cas d'utilisation, mais je vous encourage vivement à envisager de repenser votre flux d'utilisateurs de votre application et si la suggestion de conception suivante peut être mise en œuvre.

J'ai décidé de faire quelque chose de simple que de trouver des alternatives de piratage pour onChange() en utilisant d'autres événements qui n'étaient pas vraiment destinés à cet usage (blur, click, etc.).

La façon dont je l'ai résolu:

Pré-attendez simplement une balise d’option fictive telle que select qui n’a aucune valeur.

Donc, au lieu d'utiliser simplement la structure suivante, qui nécessite des alternatives de type bidouillage:

<select>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

Pensez à utiliser ceci:

<select>
  <option selected="selected">Select...</option>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

Ainsi, de cette façon, votre code est BEAUCOUP plus simplifié et la onChange fonctionnera comme prévu, chaque fois que l'utilisateur décide de sélectionner un autre paramètre que la valeur par défaut. Vous pouvez même ajouter l'attribut disabled à la première option si vous ne souhaitez pas qu'ils le sélectionnent à nouveau et que vous les obligiez à sélectionner un élément parmi les options, ce qui déclenche un feu onChange().

Au moment de cette réponse, j'écrivais une application complexe Vue et je trouvais que ce choix de conception avait beaucoup simplifié mon code. J'ai passé des heures sur ce problème avant de régler cette solution et je n'ai pas eu à réécrire une grande partie de mon code. Cependant, si j'avais opté pour les alternatives minables, j'aurais dû prendre en compte les cas Edge, éviter le double tir des demandes ajax, etc. Cela ne gêne pas le comportement du navigateur par défaut comme un bonus de Nice (testé sur mobile). les navigateurs aussi).

Parfois, il vous suffit de prendre du recul et de réfléchir à la situation dans son ensemble pour trouver la solution la plus simple.

1
dsignr

Essayez ceci (événement déclenché exactement lorsque vous sélectionnez une option, sans changer d’option):

$("select").mouseup(function() {
    var open = $(this).data("isopen");
    if(open) {
        alert('selected');
    }
    $(this).data("isopen", !open);
});

http://jsbin.com/dowoloka/4

1
WebBrother

vous devriez essayer d'utiliser option:selected

$("select option:selected").click(doSomething);
1
Pragnesh Chauhan

tout d’abord, utilisez onChange comme gestionnaire d’événements, puis utilisez la variable flag pour lui permettre de faire la fonction à chaque fois que vous effectuez un changement.

<select
var list = document.getElementById("list");
var flag = true ; 
list.onchange = function () {
if(flag){
document.bgColor ="red";
flag = false;

}else{
document.bgColor ="green";
flag = true;
}
}
<select id="list"> 
<option>op1</option>
<option>op2</option>
<option>op3</option>
</select>
1
Paula George
<select name="test[]" 
onchange="if(this.selectedIndex < 1){this.options[this.selectedIndex].selected = !1}">
<option>1</option>
<option>2</option>
<option>3</option>
</select>
0
xicooc

La seule vraie réponse est de ne pas utiliser le champ de sélection (si vous devez faire quelque chose lorsque vous re-sélectionnez la même réponse).

Créez un menu déroulant avec un menu conventionnel div, bouton, afficher/masquer. Lien: https://www.w3schools.com/howto/howto_js_dropdown.asp

Cela aurait pu être évité si l'on avait pu ajouter des écouteurs d'événements aux options. S'il y avait eu un écouteur onSelect pour l'élément select. Et si le fait de cliquer sur le champ de sélection ne déclenche pas de manière agressive Mousedown, MousUp et tout en même temps sur Mousedown.

0
Shinjitsu

Essaye ça:

<select id="nameSelect" onfocus="javascript:document.getElementById('nameSelect').selectedIndex=-1;" onchange="doSomething(this);">
    <option value="A">A</option>
    <option value="B">B</option>
    <option value="C">C</option>
</select>
0
Jesús López

J'avais fait face à un besoin similaire et fini par écrire une directive angularjs pour la même chose -

lien guthub - angular select

Utilisé element[0].blur(); pour supprimer le focus de la balise select. La logique est de déclencher ce flou au deuxième clic de la liste déroulante.

as-select est déclenché même lorsque l'utilisateur sélectionne la même valeur dans la liste déroulante.

DEMO - lien

0
Nithin Kumar Biliya

Cela fait longtemps maintenant mais en réponse à la question initiale, cela aiderait-il? Il suffit de mettre onClick dans la ligne SELECT. Puis mettez ce que vous voulez que chaque OPTION fasse dans les lignes OPTION. c'est à dire:

<SELECT name="your name" onClick>
<option value ="Kilometres" onClick="YourFunction()">Kilometres
-------
-------
</SELECT>
0
bones