Obtenir la valeur de select (liste déroulante) avant le changement


237

Ce que je veux réaliser, c'est que chaque fois que la <select>liste déroulante est modifiée, je veux la valeur de la liste déroulante avant le changement. J'utilise la version 1.3.2 de jQuery et j'utilise l'événement on change, mais la valeur que j'obtiens là-bas est après le changement.

<select name="test">
<option value="stack">Stack</option>
<option value="overflow">Overflow</option>
<option value="my">My</option>
<option value="question">Question</option>
</select>

Disons que l'option actuellement My est sélectionnée maintenant lorsque je la change en pile dans l'événement onchange (c'est-à-dire quand je la change en pile) Je veux que sa valeur précédente soit ma attendue dans ce cas.

Comment cela peut il etre accompli?

Edit: Dans mon cas, j'ai plusieurs cases de sélection sur la même page et je veux que la même chose soit appliquée à toutes. De plus, toutes mes sélections sont insérées après le chargement de la page via ajax.


1
Avez-vous vérifié cela: stackoverflow.com/questions/1983535/…
Rajat

Réponses:


434

Combinez l' événement focus avec l' événement change pour obtenir ce que vous voulez:

(function () {
    var previous;

    $("select").on('focus', function () {
        // Store the current value on focus and on change
        previous = this.value;
    }).change(function() {
        // Do something with the previous value after the change
        alert(previous);

        // Make sure the previous value is updated
        previous = this.value;
    });
})();

Exemple de travail: http://jsfiddle.net/x5PKf/766


1
@Alpesh: Malheureusement non, puisque vous n'utilisez pas jQuery 1.4.1 ou une version ultérieure, vous ne pouvez pas utiliser live () avec les événements focus et change . La seule chose que vous pourriez faire est d'ajuster votre script pour qu'il se lie après que les éléments sont insérés dans la page.
Andy E

1
Merci, j'ai déjà lié les deux avec le live et cela a fonctionné avec succès. :)
Alpesh

4
Notez que vous devez également vous concentrer sur l'élément sélectionné dans votre gestionnaire de modifications, sinon il ne sera pas déclenché après un changement de valeur répété
Alex

52
Je ne suis pas d'accord avec cette solution. Si vous modifiez la valeur une fois, cela fonctionnera, mais si vous le faites une fois de plus, cela ne fonctionnera pas. Vous devez cliquer quelque part pour perdre le focus et un autre clic sur la liste déroulante. Je suggère: $ ("# dropdownId"). On ('change', function () {var ddl = $ (this); var previous = ddl.data ('previous'); ddl.data ('previous', ddl .val ());});
free4ride

5
@ free4ride, pour corriger ce que je viens d'appeler $(this).blur();à la fin de la fonction de changement
chiliNUT

135

veuillez ne pas utiliser de var globale pour cela - stockez la valeur précédente dans les données voici un exemple: http://jsbin.com/uqupu3/2/edit

le code pour ref:

$(document).ready(function(){
  var sel = $("#sel");
  sel.data("prev",sel.val());

  sel.change(function(data){
     var jqThis = $(this);
     alert(jqThis.data("prev"));
     jqThis.data("prev",jqThis.val());
  });
});

vient de voir que vous avez de nombreux choix sur la page - cette approche fonctionnera également pour vous car pour chaque sélection, vous stockerez la valeur précédente sur les données de la sélection


jQuery.data est une bonne solution ici. à votre solution, vous créez une fermeture pour chaque sélection qui a un impact sur la performance s'il y a beaucoup d'éléments sélectionnés
Avi Pinto

Ma préoccupation n'était pas la performance, et je ne suis pas convaincu que la création de fonctions soit plus lente que de jQuery.datatoute façon.
August Lilleaas,

9
quelle est votre objection à l'utilisation de jQuery.data? pour autant que je sache, la bibliothèque jQuery l'utilise également en interne et recommande de l'utiliser
Avi Pinto

Je suis tout à fait d'accord avec l'utilisation de jQuery Data - merci de me rappeler que j'allais utiliser la var globale .. Rien de mal avec la var globale mais l'utilisation des données est plus concise. Mais enchaîner le focus puis le changement est aussi bien :)
Piotr Kula

4
@ppumkin: Une chose est vraiment fausse avec une variable globale: elle ne prend en charge qu'une seule select! La réponse acceptée sera rompue car elle correspond à tous, selectmais ne stocke que la valeur de la première. data est la meilleure façon de le faire. +1 :)
Fin du codage du

86

Je choisis la solution d'Avi Pinto qui utilise jquery.data()

L'utilisation de focus n'est pas une solution valable. Cela fonctionne la première fois que vous modifiez les options, mais si vous restez sur cet élément de sélection, et appuyez sur la touche "haut" ou "bas". Il ne passera plus par l'événement focus.

Donc, la solution devrait ressembler davantage à ce qui suit,

//set the pre data, usually needed after you initialize the select element
$('mySelect').data('pre', $(this).val());

$('mySelect').change(function(e){
    var before_change = $(this).data('pre');//get the pre data
    //Do your work here
    $(this).data('pre', $(this).val());//update the pre data
})

3
Excellente solution, bien meilleure que la réponse sélectionnée!
TJL

2
La deuxième partie fonctionne bien, mais la première partie ne définit pas l'attribut de données. Des idées?
Sinaesthetic

1
@Sinaesthetic, j'ai eu le même problème (et j'ai déjà voté pour cette réponse). Je ne pense pas que $ (this) survit à la méthode .data (). La réponse d'Avi Pinto remonte à l'élément select pour sa valeur, et cela a fonctionné pour moi (j'ai donc également voté pour Avi).
goodeye

1
Cela ne fonctionnera pas depuis cela! == $ ('mySelect'). Voici une version fixe. var $selectStatus = $('.my-select'); $selectStatus.on('change', function () { var newStatus = $(this).val(); var oldStatus = $(this).data('pre'); }).data('pre', $selectStatus.val());
Capy

2
@Sinaesthetic cette ligne définit une valeur pour tous les éléments "mySelect" $('mySelect').data('pre', $(this).val());Cela devrait être comme: $('mySelect').each(function() { $(this).data('pre', $(this).val()); });Je n'ai pas assez de réputation pour éditer la réponse: /
Abderrahim

8

Suivez la valeur à la main.

var selects = jQuery("select.track_me");

selects.each(function (i, element) {
  var select = jQuery(element);
  var previousValue = select.val();
  select.bind("change", function () {
    var currentValue = select.val();

    // Use currentValue and previousValue
    // ...

    previousValue = currentValue;
  });
});

Je ne peux pas utiliser l'approche ci-dessus parce que j'ai plusieurs cases de sélection dans cette même page avec lesquelles je dois traiter.
Alpesh

1
Vous n'avez rien dit à propos de plusieurs boutons de sélection dans votre question. J'ai mis à jour ma réponse pour prendre en charge plusieurs boîtes.
August Lilleaas

1
meilleure réponse. Je pense que cette solution est meilleure que l'utilisation de focus () et change () car elle repose sur jquery pour la compatibilité du navigateur, puis sur l'exécution correcte du flux ef des deux méthodes
coorasse

@coorasse: le bon déroulement de l'exécution ne pourra jamais être différent. Une valeur de sélection de boîtes n'a jamais pu être modifiée par l'utilisateur avant que l'élément prenne le focus. Cela étant dit, il n'y a rien de mal à cette approche non plus :-)
Andy E

Du point de vue de l'utilisation de la «fermeture», je ne sais pas si c'est mieux que la solution «concentrée».
James Poulose

8
 $("#dropdownId").on('focus', function () {
    var ddl = $(this);
    ddl.data('previous', ddl.val());
}).on('change', function () {
    var ddl = $(this);
    var previous = ddl.data('previous');
    ddl.data('previous', ddl.val());
});

Cela a fonctionné pour moi, seule une légère correction est sur le sélecteur dropdownId, c'est
activé

2
L'événement de changement peut se produire sans interaction de l'utilisateur, donc ce n'est pas une évidence
qdev

3

J'utilise l'événement "live", ma solution est fondamentalement similaire à Dimitiar, mais au lieu d'utiliser "focus", ma valeur précédente est stockée lorsque "click" est déclenché.

var previous = "initial prev value";
$("select").live('click', function () {
        //update previous value
        previous = $(this).val();
    }).change(function() {
        alert(previous); //I have previous value 
    });

2
Je n'utiliserais pas ça. Que se passe-t-il si l'utilisateur «tabule» l'élément de sélection et utilise ses flèches de clavier pour sélectionner une option différente?
Christian Lundahl

@Perplexor oui, cela ne fonctionnera pas avec les touches, sinon il stockera chaque valeur à chaque fois que vous appuyez sur la touche. Cela suppose seulement que l'utilisateur clique sur le menu déroulant. Le problème est que l'événement 'live' ne fonctionnera pas avec 'focus', je ne connais pas de meilleure solution.
Cica Gustiani

Vous pouvez stocker la valeur actuelle sur le focus dans une variable distincte. C'est juste du haut de ma tête, donc je ne sais pas si c'est idéal.
Christian Lundahl

Si la «concentration» peut fonctionner avec un événement «en direct», ce sera parfait. Mais si vous créez dynamiquement ces menus déroulants, vous ne pouvez utiliser que «live», c'est ce que je sais. Le «focus» sur le «live» ne déclenche pas l'événement pour stocker les nouvelles valeurs, malheureusement, mais je ne sais pas avec le nouveau jquery
Cica Gustiani

live is dead dans les nouvelles versions de jQuery! [ stackoverflow.com/questions/14354040/…
remo

2

conservez la valeur déroulante actuellement sélectionnée avec jquery choisi dans une variable globale avant d'écrire la fonction d'action déroulante 'on change'. Si vous souhaitez définir la valeur précédente dans la fonction, vous pouvez utiliser la variable globale.

//global variable
var previousValue=$("#dropDownList").val();
$("#dropDownList").change(function () {
BootstrapDialog.confirm(' Are you sure you want to continue?',
  function (result) {
  if (result) {
     return true;
  } else {
      $("#dropDownList").val(previousValue).trigger('chosen:updated');  
     return false;
         }
  });
});

1

Que diriez-vous d'utiliser un événement jQuery personnalisé avec une interface de type montre angulaire;

// adds a custom jQuery event which gives the previous and current values of an input on change
(function ($) {
    // new event type tl_change
    jQuery.event.special.tl_change = {
        add: function (handleObj) {
            // use mousedown and touchstart so that if you stay focused on the
            // element and keep changing it, it continues to update the prev val
            $(this)
                .on('mousedown.tl_change touchstart.tl_change', handleObj.selector, focusHandler)
                .on('change.tl_change', handleObj.selector, function (e) {
                // use an anonymous funciton here so we have access to the
                // original handle object to call the handler with our args
                var $el = $(this);
                // call our handle function, passing in the event, the previous and current vals
                // override the change event name to our name
                e.type = "tl_change";
                handleObj.handler.apply($el, [e, $el.data('tl-previous-val'), $el.val()]);
            });
        },
        remove: function (handleObj) {
            $(this)
                .off('mousedown.tl_change touchstart.tl_change', handleObj.selector, focusHandler)
                .off('change.tl_change', handleObj.selector)
                .removeData('tl-previous-val');
        }
    };

    // on focus lets set the previous value of the element to a data attr
    function focusHandler(e) {
        var $el = $(this);
        $el.data('tl-previous-val', $el.val());
    }
})(jQuery);

// usage
$('.some-element').on('tl_change', '.delegate-maybe', function (e, prev, current) {
    console.log(e);         // regular event object
    console.log(prev);      // previous value of input (before change)
    console.log(current);   // current value of input (after change)
    console.log(this);      // element
});

1

Je sais que c'est un vieux fil, mais j'ai pensé pouvoir ajouter un petit plus. Dans mon cas, je voulais transmettre le texte, val et quelques autres données attr. Dans ce cas, il vaut mieux stocker toute l'option en tant que valeur précédente plutôt que juste la valeur.

Exemple de code ci-dessous:

var $sel = $('your select');
$sel.data("prevSel", $sel.clone());
$sel.on('change', function () {
    //grab previous select
    var prevSel = $(this).data("prevSel");

    //do what you want with the previous select
    var prevVal = prevSel.val();
    var prevText = prevSel.text();
    alert("option value - " + prevVal + " option text - " + prevText)

    //reset prev val        
    $(this).data("prevSel", $(this).clone());
});

ÉDITER:

J'ai oublié d'ajouter .clone () sur l'élément. à ne pas le faire lorsque vous essayez de retirer les valeurs que vous finissez par extraire la nouvelle copie de la sélection plutôt que la précédente. L'utilisation de la méthode clone () stocke une copie de la sélection au lieu d'une instance de celle-ci.


0

Eh bien, pourquoi ne stockez-vous pas la valeur sélectionnée actuelle, et lorsque l'élément sélectionné est modifié, vous conserverez l'ancienne valeur? (et vous pouvez le mettre à jour à votre guise)


Eh bien, je ne peux pas le faire parce que dans mon cas, j'ai plusieurs cases de sélection sur cette même page. Et sauvegarder la valeur initiale de tous au début sera trop fastidieux.
Alpesh

0

Utilisez le code suivant, je l'ai testé et son fonctionnement

var prev_val;
$('.dropdown').focus(function() {
    prev_val = $(this).val();
}).change(function(){
            $(this).unbind('focus');
            var conf = confirm('Are you sure want to change status ?');

            if(conf == true){
                //your code
            }
            else{
                $(this).val(prev_val);
                $(this).bind('focus');
                return false;
            }
});

0
(function() {

    var value = $('[name=request_status]').change(function() {
        if (confirm('You are about to update the status of this request, please confirm')) {
            $(this).closest('form').submit(); // submit the form
        }else {
            $(this).val(value); // set the value back
        }
    }).val();
})();

0

Je voudrais contribuer une autre option pour résoudre ce problème; car les solutions proposées ci-dessus n'ont pas résolu mon scénario.

(function()
    {
      // Initialize the previous-attribute
      var selects = $('select');
      selects.data('previous', selects.val());

      // Listen on the body for changes to selects
      $('body').on('change', 'select',
        function()
        {
          $(this).data('previous', $(this).val());
        }
      );
    }
)();

Cela utilise jQuery pour que def. est une dépendance ici, mais cela peut être adapté pour fonctionner en javascript pur. (Ajoutez un écouteur au corps, vérifiez si la cible d'origine était une fonction select, execute, ...).

En attachant l'écouteur de modification au corps, vous pouvez être sûr que cela se déclenchera après des écouteurs spécifiques pour les sélections, sinon la valeur de 'data-previous' sera écrasée avant même que vous ne puissiez la lire.

Cela suppose bien sûr que vous préférez utiliser des écouteurs séparés pour votre valeur précédente et votre valeur de contrôle. Cela correspond parfaitement au modèle de responsabilité unique.

Remarque: Cela ajoute cette fonctionnalité «précédente» à toutes les sélections, veillez donc à affiner les sélecteurs si nécessaire.


0

Il s'agit d'une amélioration par rapport à la réponse @thisisboris. Il ajoute une valeur actuelle aux données, afin que le code puisse contrôler quand une variable définie sur la valeur actuelle est modifiée.

(function()
{
    // Initialize the previous-attribute
    var selects = $( 'select' );
    $.each( selects, function( index, myValue ) {
        $( myValue ).data( 'mgc-previous', myValue.value );
        $( myValue ).data( 'mgc-current', myValue.value );  
    });

    // Listen on the body for changes to selects
    $('body').on('change', 'select',
        function()
        {
            alert('I am a body alert');
            $(this).data('mgc-previous', $(this).data( 'mgc-current' ) );
            $(this).data('mgc-current', $(this).val() );
        }
    );
})();

0

Meilleure solution:

$('select').on('selectric-before-change', function (event, element, selectric) {
    var current = element.state.currValue; // index of current value before select a new one
    var selected = element.state.selectedIdx; // index of value that will be selected

    // choose what you need
    console.log(element.items[current].value);
    console.log(element.items[current].text);
    console.log(element.items[current].slug);
});

1
cette réponse est basée sur la bibliothèque js "Selectric", et non sur jQuery "ordinaire" ou javascript. Bien que ce soit le meilleur, il ne convient pas à la question d'origine ni ne dit que l'utilisateur doit installer autre chose pour que cela fonctionne
gadget00

0

Il existe plusieurs façons d'atteindre le résultat souhaité, c'est ma façon humble de le faire:

Laissez l'élément conserver sa valeur précédente, alors ajoutez un attribut 'previousValue'.

<select id="mySelect" previousValue=""></select>

Une fois initialisé, «previousValue» pouvait désormais être utilisé comme attribut. Dans JS, pour accéder à la valeur précédente de cette sélection:

$("#mySelect").change(function() {console.log($(this).attr('previousValue'));.....; $(this).attr('previousValue', this.value);}

Une fois que vous avez terminé d'utiliser «previousValue», mettez à jour l'attribut à sa valeur actuelle.


0

Je devais révéler un div différent en fonction de la sélection

Voici comment vous pouvez le faire avec la syntaxe jquery et es6

HTML

<select class="reveal">
    <option disabled selected value>Select option</option>
    <option value="value1" data-target="#target-1" >Option 1</option>
    <option value="value2" data-target="#target-2" >Option 2</option>
</select>
<div id="target-1" style="display: none">
    option 1
</div>
<div id="target-2" style="display: none">
    option 2
</div>

JS

$('select.reveal').each((i, element)=>{
    //create reference variable 
    let $option = $('option:selected', element)
    $(element).on('change', event => {
        //get the current select element
        let selector = event.currentTarget
        //hide previously selected target
        if(typeof $option.data('target') !== 'undefined'){
            $($option.data('target')).hide()
        }
        //set new target id
        $option = $('option:selected', selector)
        //show new target
        if(typeof $option.data('target') !== 'undefined'){
            $($option.data('target')).show()
        }
    })
})
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.