Ottenere il valore di select (menu a discesa) prima della modifica


237

La cosa che voglio ottenere è ogni volta che il <select>menu a discesa viene modificato. Voglio il valore del menu a discesa prima della modifica. Sto usando la versione 1.3.2 di jQuery e l'utilizzo in caso di cambiamento ma il valore che sto superando è dopo il cambiamento.

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

Diciamo che attualmente l'opzione My è selezionata ora quando la cambio per impilare nell'evento onchange (cioè quando l'ho cambiata per impilare) Voglio il suo valore precedente, cioè il mio previsto in questo caso.

Come si può ottenere questo?

Modifica: nel mio caso ho più caselle di selezione nella stessa pagina e voglio che la stessa cosa venga applicata a tutte. Inoltre, tutte le mie selezioni vengono inserite dopo il caricamento della pagina tramite Ajax.


Risposte:


434

Combina l' evento focus con l' evento change per ottenere ciò che desideri:

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

Esempio di lavoro: http://jsfiddle.net/x5PKf/766


1
@Alpesh: Sfortunatamente no, poiché non stai usando jQuery 1.4.1 o versioni successive, non puoi utilizzare live () con lo stato attivo e modificare gli eventi. L'unica cosa che puoi fare è regolare lo script in modo che si leghi dopo che gli elementi sono stati inseriti nella pagina.
Andy E

1
Grazie ho già vincolato entrambi con live e ha funzionato con successo. :)
Alpesh,

4
Tieni presente che dovresti anche focalizzare l'elemento select nel gestore delle modifiche, altrimenti non verrà attivato dopo ripetute modifiche del valore
Alex,

52
Non sono d'accordo con questa soluzione. Se modifichi il valore una volta che funzionerà, ma se lo fai ancora una volta non lo farà. Devi fare clic da qualche parte per perdere la messa a fuoco e un altro clic sul menu a discesa. Suggerisco: $ ("# dropdownId"). On ('change', function () {var ddl = $ (this); var precedente = ddl.data ('precedente'); ddl.data ('precedente', ddl .val ());});
free4ride,

5
@ free4ride, per risolvere il problema che ho appena chiamato $(this).blur();alla fine della funzione di modifica
chiliNUT

135

per favore non usare una var globale per questo - memorizza il valore precedente nei dati qui è un esempio: http://jsbin.com/uqupu3/2/edit

il codice per 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());
  });
});

ho appena visto che hai molte selezioni sulla pagina - questo approccio funzionerà anche per te poiché per ogni selezione memorizzerai il valore precedente sui dati della selezione


jQuery.data è una buona soluzione qui. alla tua soluzione stai creando una chiusura per ogni selezione che ha un impatto perfetto se ci sono molti elementi selezionati
Avi Pinto

La mia preoccupazione non riguardava le prestazioni e non sono convinto che la creazione di funzioni sia più lenta che jQuery.datacomunque.
August Lilleaas,

9
quindi qual è la tua obiezione per l'utilizzo di jQuery.data? per quanto ne so la libreria jQuery la usa anche internamente e mi consiglia di usarla
Avi Pinto

Sicuramente d'accordo con l'utilizzo di jQuery Data, grazie per avermi ricordato che stavo per usare la var globale. Nulla di sbagliato con var globale ma usare i dati è più conciso. Ma concatenare l'attenzione e poi il cambiamento è anche bello :)
Piotr Kula,

4
@ppumkin: una cosa sicuramente sbagliata con una variabile globale: ne supporta solo una select! La risposta accettata si interromperà poiché corrisponde a tutte, selectma memorizza solo il valore della prima. data è il modo migliore per farlo. +1 :)
Codice andato finito il

86

Vado per la soluzione di Avi Pinto che utilizza jquery.data()

L'uso di focus non è una soluzione valida. Funziona alla prima modifica delle opzioni, ma se rimani su quell'elemento selezionato e premi il tasto "su" o "giù". Non passerà di nuovo attraverso l'evento focus.

Quindi la soluzione dovrebbe essere più simile alla seguente,

//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
Ottima soluzione, molto meglio della risposta selezionata!
TJL

2
La seconda parte funziona correttamente, ma la prima parte non imposta l'attributo di dati. Qualche idea?
Sinaesthetic

1
@Sinaesthetic, ho avuto lo stesso problema (e ho già votato a favore di questa risposta). Non credo che $ (questo) sopravviva al metodo .data (). La risposta di Avi Pinto risale all'elemento selezionato per il suo valore, e questo ha funzionato per me (quindi ho votato anche su Avi).
arrivederci,

1
Questo non funzionerà da allora! == $ ('mySelect'). Ecco una versione fissa. var $selectStatus = $('.my-select'); $selectStatus.on('change', function () { var newStatus = $(this).val(); var oldStatus = $(this).data('pre'); }).data('pre', $selectStatus.val());
Capy,

2
@Sinaesthetic questa riga imposta un valore per tutti gli elementi "mySelect" $('mySelect').data('pre', $(this).val());Dovrebbe essere come: $('mySelect').each(function() { $(this).data('pre', $(this).val()); });Non ho abbastanza reputazione per modificare la risposta: /
Abderrahim

8

Tieni traccia del valore a mano.

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

Non riesco ad usare l'approccio sopra perché ho più caselle di selezione in quella stessa pagina con cui devo fare i conti.
Alpesh,

1
Non hai detto nulla riguardo a più pulsanti di selezione nella tua domanda. Tuttavia, ho aggiornato la mia risposta per supportare più caselle.
August Lilleaas,

1
migliore risposta. Penso che questa soluzione sia meglio di usign focus () e change () perché si basa su jquery per la compatibilità del browser raither quindi sul flusso corretto e sull'esecuzione di entrambi i metodi
coorasse

@coorasse: il corretto flusso di esecuzione non potrebbe mai essere diverso. Un valore di caselle selezionate non può mai essere modificato dall'utente prima che l'elemento venga attivato. Detto questo, non c'è nulla di sbagliato in questo approccio :-)
Andy E

Dal punto di vista dell'uso della "chiusura", non sono sicuro che sia meglio della soluzione "focus".
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());
});

Questo ha funzionato per me solo una leggera correzione è sul menu a
discesaId

2
L'evento di modifica può verificarsi senza l'interazione dell'utente, quindi non è un
problema

3

Sto usando l'evento "live", la mia soluzione è sostanzialmente simile a Dimitiar, ma invece di usare "focus", il mio valore precedente viene memorizzato quando viene attivato "click".

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

2
Non lo userei. Che cosa succede se l'utente "tocca" l'elemento select e usa le frecce della sua tastiera per selezionare un'opzione diversa?
Christian Lundahl,

@Perplexor sì, non funzionerà con i tasti, altrimenti memorizzerà ogni valore ogni volta che premi il tasto. Ciò presuppone che l'utente faccia clic sul menu a discesa. Il problema è che l'evento "live" non funzionerà con "focus", non conosco alcuna soluzione migliore.
Cica Gustiani,

È possibile memorizzare il valore corrente attivo in una variabile separata. Questo è solo dalla cima della mia testa, quindi non sono sicuro che sia l'ideale.
Christian Lundahl,

Se "focus" può funzionare con l'evento "live", sarà perfetto. Ma se crei dinamicamente quei menu a discesa, puoi usare solo "live", questo è quello che so. Il "focus" su "live" non attiva l'evento per memorizzare i nuovi valori, sfortunatamente, ma non lo so con il nuovo jquery
Cica Gustiani,

live è morto nelle nuove versioni di jQuery! [ stackoverflow.com/questions/14354040/…
rimuovi il

2

mantenere il valore a discesa attualmente selezionato con jquery selezionato in una variabile globale prima di scrivere la funzione di azione "al cambio". Se si desidera impostare il valore precedente nella funzione, è possibile utilizzare la variabile 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

Che ne dite di usare un evento jQuery personalizzato con un'interfaccia di tipo watch angolare;

// 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

So che questo è un vecchio thread, ma ho pensato di aggiungere un piccolo extra. Nel mio caso volevo trasmettere il testo, val e alcuni altri dati attr. In questo caso è meglio memorizzare l'intera opzione come valore prev anziché solo val.

Esempio di codice di seguito:

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

MODIFICARE:

Ho dimenticato di aggiungere .clone () all'elemento. nel non farlo quando provi a ritirare i valori che finisci per inserire la nuova copia della selezione piuttosto che la precedente. L'uso del metodo clone () memorizza una copia di select anziché un'istanza di essa.


0

Bene, perché non memorizzi il valore attualmente selezionato e quando l'elemento selezionato viene modificato, il vecchio valore verrà archiviato? (e puoi aggiornarlo di nuovo come desideri)


Beh, non posso farlo perché nel mio caso ho più caselle di selezione in quella stessa pagina. E salvare il valore iniziale di tutto all'inizio sarà troppo complicato.
Alpesh,

0

Usa il seguente codice, l'ho testato e funziona

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

Vorrei contribuire con un'altra opzione per risolvere questo problema; poiché le soluzioni sopra proposte non hanno risolto il mio scenario.

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

Questo utilizza jQuery in modo che def. è una dipendenza qui, ma questo può essere adattato per funzionare in javascript puro. (Aggiungi un ascoltatore al corpo, controlla se l'obiettivo originale era una selezione, esegui la funzione, ...).

Collegando l'ascoltatore di modifiche al corpo, puoi quasi essere certo che questo verrà attivato dopo specifici ascoltatori per le selezioni, altrimenti il ​​valore di 'data-precedente' verrà sovrascritto prima ancora di poterlo leggere.

Questo ovviamente presuppone che tu preferisca usare ascoltatori separati per il tuo set-precedente e il valore di controllo. Si adatta perfettamente al modello a responsabilità singola.

Nota: questo aggiunge questa funzionalità 'precedente' a tutte le selezioni, quindi assicurati di mettere a punto i selettori se necessario.


0

Questo è un miglioramento sulla risposta di @thisisboris. Aggiunge un valore corrente ai dati, quindi il codice può controllare quando viene modificata una variabile impostata sul valore corrente.

(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

Soluzione migliore:

$('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
questa risposta si basa sulla libreria js "Selectric" e non su jQuery o javascript "semplici". Anche se è il migliore, non soddisfa la domanda originale né dice che l'utente deve installare qualcos'altro per farlo funzionare
gadget00

0

Esistono diversi modi per ottenere il risultato desiderato, questo è il mio modesto modo di farlo:

Lascia che l'elemento mantenga il suo valore precedente, quindi aggiungi un attributo 'previousValue'.

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

Una volta inizializzato, 'previousValue' poteva ora essere usato come attributo. In JS, per accedere al valore precedente di questo selezionare:

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

Dopo aver finito di usare "previousValue", aggiorna l'attributo al valore corrente.


0

Avevo bisogno di rivelare un div diverso in base alla selezione

Ecco come puoi farlo con la sintassi jquery ed 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()
        }
    })
})
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.