Uzyskiwanie wartości select (menu rozwijane) przed zmianą


237

To, co chcę osiągnąć, to ilekroć <select>lista rozwijana jest zmieniana. Chcę wartość listy rozwijanej przed zmianą. Korzystam z jQuery w wersji 1.3.2 i używam przy zdarzeniu zmiany, ale wartość, którą tam otrzymuję, jest po zmianie.

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

Powiedzmy, że obecnie opcja My jest wybrana teraz, kiedy zmieniam ją na stos w zdarzeniu onchange (tj. Kiedy zmieniłem ją na stos) Chcę, aby była to poprzednia wartość, tj. Moja oczekiwana w tym przypadku.

Jak można to osiągnąć?

Edycja: W moim przypadku mam wiele pól wyboru na tej samej stronie i chcę, aby wszystkie te same elementy były stosowane. Również wszystkie moje zaznaczenia są wstawiane po załadowaniu strony przez ajax.


Odpowiedzi:


434

Połącz zdarzenie skupienia ze zdarzeniem zmiany , aby osiągnąć to, co chcesz:

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

Przykład roboczy: http://jsfiddle.net/x5PKf/766


1
@Alpesh: Niestety nie, ponieważ nie używasz jQuery 1.4.1 lub nowszej wersji, nie możesz używać live () z fokusem i zmianą zdarzeń. Jedyne, co możesz zrobić, to dostosować skrypt do wiązania po wstawieniu elementów na stronę.
Andy E,

1
Dzięki, że już związałem się z liveem i udało się. :)
Alpesh,

4
Pamiętaj, że powinieneś także skoncentrować się na elemencie select w module obsługi zmiany, w przeciwnym razie nie zostanie on wyzwolony po powtarzającej się zmianie wartości
Alex

52
Nie zgadzam się z tym rozwiązaniem. Jeśli raz zmienisz wartość, to zadziała, ale jeśli zrobisz to jeszcze raz, nie będzie. Musisz gdzieś kliknąć, aby stracić koncentrację, a następnie kliknąć menu rozwijane. Sugeruję: $ ("# dropdownId"). On ('change', function () {var ddl = $ (this); var previous = ddl.data ('previous'); ddl.data ('previous', ddl .val ());});
free4ride

5
@ free4ride, aby to naprawić, po prostu dzwonię $(this).blur();na końcu funkcji zmiany
chiliNUT

135

nie używaj do tego globalnego var - zapisz poprzednią wartość w danych tutaj jest przykład: http://jsbin.com/uqupu3/2/edit

kod referencyjny:

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

właśnie zobaczyłem, że masz wiele wyborów na stronie - to podejście również zadziała, ponieważ dla każdego wyboru zapiszesz poprzednią wartość na danych wybranego


jQuery.data jest tutaj dobrym rozwiązaniem. w swoim rozwiązaniu tworzysz zamknięcie dla każdego wyboru, które ma doskonały wpływ, jeśli istnieje wiele wybranych elementów
Avi Pinto,

Moją troską nie była wydajność i nie jestem przekonany, że tworzenie funkcji jest wolniejsze niż i jQuery.datatak.
August Lilleaas,

9
więc jaki jest twój sprzeciw wobec używania jQuery.data? o ile wiem, biblioteka jQuery również korzysta z niej wewnętrznie i zaleca jej używanie
Avi Pinto,

Zdecydowanie zgadzam się na użycie jQuery Data - dziękuję za przypomnienie, że miałem użyć globalnego var. Nic nie jest złe z globalnym var, ale używanie danych jest bardziej zwięzłe. Ale łączenie skupienia, a następnie zmiana jest również miłe :)
Piotr Kula,

4
@ppumkin: Jedna rzecz jest zdecydowanie nie tak ze zmienną globalną: Obsługuje tylko jedną select! Akceptowana odpowiedź zostanie przerwana, ponieważ pasuje do wszystkich, selectale tylko przechowuje wartość pierwszej. data jest lepszym sposobem na zrobienie tego. +1 :)
Koniec kodowania

86

Wybieram rozwiązanie Avi Pinto, które wykorzystuje jquery.data()

Używanie fokusa nie jest prawidłowym rozwiązaniem. Działa przy pierwszej zmianie opcji, ale jeśli pozostaniesz na tym wybranym elemencie i naciśniesz klawisz „w górę” lub „w dół”. Nie przejdzie ponownie przez zdarzenie skupienia.

Tak więc rozwiązanie powinno wyglądać następująco:

//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
Świetne rozwiązanie, znacznie lepsze niż wybrana odpowiedź!
TJL,

2
Druga część działa dobrze, ale pierwsza nie ustawia atrybutu danych. Jakieś pomysły?
Sinaesthetic

1
@Sestestetyczne, miałem ten sam problem (już głosowałem tę odpowiedź). Nie sądzę, aby $ (this) przetrwał metodę .data (). Odpowiedź Avi Pinto wraca do elementu select ze względu na jego wartość, i to zadziałało dla mnie (dlatego też głosowałem za Avi).
goodeye,

1
To nie zadziała, ponieważ to! == $ ('mySelect'). Oto poprawiona wersja. var $selectStatus = $('.my-select'); $selectStatus.on('change', function () { var newStatus = $(this).val(); var oldStatus = $(this).data('pre'); }).data('pre', $selectStatus.val());
Capy

2
@Sinaesthetic ten wiersz ustawia jedną wartość dla wszystkich elementów „mySelect” $('mySelect').data('pre', $(this).val());Powinno być tak: $('mySelect').each(function() { $(this).data('pre', $(this).val()); });Nie mam wystarczającej reputacji, aby edytować odpowiedź: /
Abderrahim

8

Śledź wartość ręcznie.

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

Nie mogę użyć powyższego podejścia, ponieważ mam wiele pól wyboru na tej samej stronie, z którymi mam do czynienia.
Alpesh,

1
W swoim pytaniu nic nie powiedziałeś o wielu przyciskach wyboru. Zaktualizowałem moją odpowiedź, aby obsługiwała wiele skrzynek.
August Lilleaas,

1
najlepsza odpowiedź. Myślę, że to rozwiązanie jest lepsze niż usign focus () i change (), ponieważ polega on na jquery w celu zapewnienia kompatybilności przeglądarki, a następnie poprawnym wykonaniu obu metod
coorasse

@coorasse: poprawny przepływ wykonania nigdy nie może być inny. Użytkownik nie może nigdy zmienić wartości pól wyboru, dopóki element nie zostanie zogniskowany. Biorąc to pod uwagę, nie ma nic złego w tym podejściu :-)
Andy E

Z punktu widzenia użycia „zamknięcia” nie jestem pewien, czy jest to lepsze niż rozwiązanie „skoncentrowane”.
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());
});

To działało dla mnie tylko niewielka korekta jest na rozwijanym selektorze, a zamiast jednego, dzięki
malkoty,

2
Zmiana zdarzenia może nastąpić bez interakcji użytkownika, więc nie jest to
proste

3

Używam zdarzenia „na żywo”, moje rozwiązanie jest w zasadzie podobne do Dimitiar, ale zamiast „skupienia” moja poprzednia wartość jest zapisywana po uruchomieniu „kliknięcia”.

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

2
Nie użyłbym tego. Co się stanie, jeśli użytkownik przejdzie do elementu wyboru i użyje strzałek na klawiaturze, aby wybrać inną opcję?
Christian Lundahl,

@Perplexor tak, nie będzie działać z kluczami, w przeciwnym razie będzie przechowywać każdą wartość za każdym razem, gdy naciśniesz klawisz. Zakłada to tylko, że użytkownik kliknie menu rozwijane. Problem polega na tym, że wydarzenie „na żywo” nie działa z „skupieniem”, nie znam lepszego rozwiązania.
Cica Gustiani

Możesz zapisać bieżącą wartość fokusa w osobnej zmiennej. To tylko z czubka mojej głowy, więc nie jestem pewien, czy to jest idealne.
Christian Lundahl

Jeśli „focus” może współpracować z wydarzeniem „na żywo”, będzie idealnie. Ale jeśli dynamicznie tworzysz te rozwijane menu, możesz używać tylko „na żywo” - to wiem. „Skoncentrowanie się” na „na żywo” nie powoduje, że wydarzenie zapamiętuje nowe wartości, niestety, ale nie wiem o nowej jquery
Cica Gustiani

live is dead w nowych wersjach jQuery! [ stackoverflow.com/questions/14354040/…
remo

2

zachowaj aktualnie wybraną wartość rozwijaną z wybraną jquery w zmiennej globalnej przed zapisaniem rozwijanej funkcji akcji „przy zmianie”. Jeśli chcesz ustawić poprzednią wartość w funkcji, możesz użyć zmiennej globalnej.

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

Co powiesz na użycie niestandardowego zdarzenia jQuery z interfejsem typu kątowego;

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

Wiem, że to stary wątek, ale pomyślałem, że mogę dodać trochę więcej. W moim przypadku chciałem przekazać tekst, val i kilka innych danych. W takim przypadku lepiej jest przechowywać całą opcję jako wartość poprzednią niż tylko wartość val.

Przykładowy kod poniżej:

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

EDYTOWAĆ:

Zapomniałem dodać .clone () do elementu. nie robiąc tego, gdy spróbujesz wycofać wartości, w końcu pobierzesz nową kopię zaznaczenia zamiast poprzedniej. Użycie metody clone () przechowuje kopię select zamiast jej instancji.


0

Dlaczego nie przechowujesz bieżącej wybranej wartości, a kiedy wybrany element zostanie zmieniony, będziesz mieć zapisaną starą wartość? (i możesz zaktualizować go ponownie, jak chcesz)


Cóż, nie mogę tego zrobić, ponieważ w moim przypadku mam wiele pól wyboru na tej samej stronie. A oszczędzanie początkowej wartości wszystkich na początku będzie zbyt żmudne.
Alpesh,

0

Użyj następującego kodu, przetestowałem go i działa

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

Chciałbym wnieść inną opcję rozwiązania tego problemu; ponieważ zaproponowane powyżej rozwiązania nie rozwiązały mojego scenariusza.

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

To używa jQuery, więc def. jest tutaj zależnością, ale można ją dostosować do pracy w czystym javascript. (Dodaj detektor do treści, sprawdź, czy pierwotny cel był funkcją select, wykonaj, ...).

Dołączając detektor zmian do treści, możesz być prawie pewien, że uruchomi się on po określonych detektorach dla selekcji, w przeciwnym razie wartość „data-previous” zostanie nadpisana, zanim będziesz w stanie ją odczytać.

Jest to oczywiście założenie, że wolisz używać osobnych detektorów dla poprzedniej wartości i wartości kontrolnej. Pasuje idealnie do wzoru pojedynczej odpowiedzialności.

Uwaga: Dodaje tę „poprzednią” funkcjonalność do wszystkich zaznaczeń, więc w razie potrzeby należy je dostroić.


0

To jest poprawa odpowiedzi @thisboris. Dodaje bieżącą wartość do danych, dzięki czemu kod może kontrolować, kiedy zmienna ustawiona na bieżącą wartość jest zmieniana.

(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

Najlepsze rozwiązanie:

$('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
ta odpowiedź jest oparta na bibliotece js „Selectric”, a nie na „zwykłym” jQuery lub javascript. Mimo że jest najlepszy, nie odpowiada pierwotnemu pytaniu ani nie mówi, że użytkownik musi zainstalować coś innego, aby działał
gadget00

0

Istnieje kilka sposobów na osiągnięcie pożądanego rezultatu, to mój skromny sposób:

Niech element zachowa poprzednią wartość, więc dodaj atrybut „previousValue”.

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

Po zainicjowaniu „previousValue” może być teraz używany jako atrybut. W JS, aby uzyskać dostęp do poprzedniej wartości tego wybierz:

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

Po zakończeniu korzystania z „previousValue” zaktualizuj atrybut do bieżącej wartości.


0

Musiałem ujawnić inny div na podstawie wyboru

W ten sposób możesz to zrobić za pomocą jquery i składni 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()
        }
    })
})
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.