249

The thing I want to achieve is whenever the <select> dropdown is changed I want the value of the dropdown before change. I am using 1.3.2 version of jQuery and using on change event but the value I am getting over there is after change.

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

Lets say currently option My is selected now when I change it to stack in the onchange event (i.e. when I changed it to stack) I want it's previous value i.e. my expected in this case.

How can this be achieved?

Edit: In my case I am having multiple select boxes in the same page and want same thing to be applied to all of them. Also all of my select are inserted after page load through ajax.

Brian Tompsett - 汤莱恩
  • 5,195
  • 62
  • 50
  • 120
Alpesh
  • 4,997
  • 2
  • 17
  • 18
  • 1
    Have you checked this out: http://stackoverflow.com/questions/1983535/dropdown-currentindex-onchange – Rajat Nov 03 '10 at 18:18

18 Answers18

460

Combine the focus event with the change event to achieve what you want:

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

Working example: http://jsfiddle.net/x5PKf/766

Dimitar Dimitrov
  • 13,563
  • 7
  • 43
  • 71
Andy E
  • 311,406
  • 78
  • 462
  • 440
  • Thanks for your solution. But the select boxes in my case are dynamic and are inserted through ajac after page load. Can you provide me solution in this case. – Alpesh Nov 02 '10 at 11:07
  • 1
    @Alpesh: Unfortunately not, since you're not using jQuery 1.4.1 or later, you're unable to use *live()* with the *focus* and *change* events. The only thing you could do is adjust your script to bind after the elements are inserted into the page. – Andy E Nov 02 '10 at 11:11
  • Thanks. will try to integrate jquery 1.4.1+ in the project. :) – Alpesh Nov 02 '10 at 11:47
  • @Alpesh: if you're successful with that, you should be able to just bind both the above events with *live()* instead. Good luck :-) – Andy E Nov 02 '10 at 11:50
  • 1
    Thanks i have already binded both with live and it worked sucessfully. :) – Alpesh Nov 02 '10 at 12:20
  • 4
    Note that you should also focus out select element in your change handler, otherwise it won't be triggered after repeated value change – Alex Nov 23 '12 at 22:08
  • @Alex: or you could just reset the `previous` var inside the change handler. – Andy E Nov 24 '12 at 12:33
  • You don't have to use focus but the answer in it's core is right: The only chance you get to solve this is to store the current selection. –  Apr 09 '13 at 12:24
  • 61
    I don't agree with this solution. If you change the value once it will work but if you do it one more time it won't. You have to click somewhere to loose focus and another click on the dropdown. I suggest: $("#dropdownId").on('change', function () { var ddl = $(this); var previous = ddl.data('previous'); ddl.data('previous', ddl.val()); }); – free4ride Jan 16 '14 at 15:12
  • @free4ride: your solution doesn't give you the previous value the first time it changes. In my solution, I'm updating the previous value in the `onchange` event as well as the `onfocus` event, so it should work just fine. Did you try it? – Andy E Jan 16 '14 at 19:36
  • @Andy E, You made the point. I posted my solution below with ".. .one('focus', ...". which should solve the problem you mentioned. Your solution works but I would use ".one('focus'" instead of ".focus" which is better in my opinion. – free4ride Jan 17 '14 at 09:00
  • @free4ride: not that it makes a noticeable difference even performance-wise, I've edited my answer to handle the `focus` event only once. Thank you for the suggestion. :-) – Andy E Jan 17 '14 at 09:07
  • You should be using apostrophes not quotes! Fixed it for ya – BAR Nov 11 '14 at 15:02
  • I am not sure, but the second argument of on must be the selector of null. See http://stackoverflow.com/questions/14354040/jquery-1-9-live-is-not-a-function – remo Mar 15 '16 at 20:49
  • 9
    @free4ride, to fix that I just call `$(this).blur();` at the end of the change function – chiliNUT Jun 23 '16 at 15:37
  • This doesn't work at all... This selects the new option I just clicked on. not the previous one. – Jeff Davenport Feb 09 '19 at 04:34
  • 1
    I this it should be `click` instead of `focus` because if user changes value multiple times the event won't get triggered. Right ?. Just and idea. – Malinda Oct 24 '19 at 17:31
  • focus event does not fire, if you change the option with arrow keys. – Sebi2020 Dec 07 '20 at 19:00
139

please don't use a global var for this - store the prev value at the data here is an example: http://jsbin.com/uqupu3/2/edit

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

just saw that you have many selects on page - this approach will also work for you since for each select you will store the prev value on the data of the select

Piotr Kula
  • 8,794
  • 8
  • 55
  • 77
Avi Pinto
  • 4,086
  • 2
  • 22
  • 21
  • jQuery.data is a good solution here. at your solution you are creating a closure for each select which has a perf impact if there are a lot of select elements – Avi Pinto Nov 02 '10 at 11:07
  • My concern was not of performance, and I'm not convinced that creating functions are slower than `jQuery.data` anyways. – August Lilleaas Nov 02 '10 at 12:00
  • 9
    so what is your objection for using jQuery.data? as far as i know the jQuery library also uses it internally, and recommends on using it – Avi Pinto Nov 02 '10 at 12:07
  • Definitely agree with using jQuery Data- thanks for reminding me I was about to use the global var.. NOthing wrong with global var but using data is more concise. But chaining focus and then change is also nice :) – Piotr Kula Jun 10 '13 at 14:44
  • 5
    @ppumkin: One thing definitely wrong with a global variable: It only supports one `select`! The accepted answer will break as it matches all `select` but only stores the value of the first one. `data` *is* the better way to do it. +1 :) – Gone Coding Jan 20 '16 at 18:04
  • @GoneCoding, definitely. I have a page for room reservations, each row is an event, so I have to disable options for rooms but only when the time of the events conflict; anyway, I have potentially a few tens of selects, so the only way to make the code manageable is to use `data`... – Francesco Marchetti-Stasi Jul 02 '20 at 09:19
88

I go for Avi Pinto's solution which uses jquery.data()

Using focus isn't a valid solution. It works at first time you change the options, but if you stay on that select element, and press key "up" or "down". It won't go through the focus event again.

So the solution should be more looks like the following,

//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
})
Himanshu Jansari
  • 28,446
  • 26
  • 101
  • 128
user1310312
  • 959
  • 7
  • 9
  • 3
    Great solution, much better than selected answer! – TJL Dec 20 '12 at 17:30
  • Thanks for pointing this out, I've updated my answer accordingly :-) – Andy E Feb 25 '13 at 17:27
  • 2
    The second part works fine but the first part isn't setting the data attribute. Any ideas? – Sinaesthetic Aug 05 '13 at 01:04
  • 1
    @Sinaesthetic, I had the same issue (and already upvoted this answer). I don't think $(this) survives the .data() method. Avi Pinto's answer goes back to the select element for its value, and this worked for me (so I upvoted Avi's as well). – goodeye Aug 16 '13 at 01:09
  • 1
    This Will not work since this !== $('mySelect'). Here is a fixed version. `var $selectStatus = $('.my-select'); $selectStatus.on('change', function () { var newStatus = $(this).val(); var oldStatus = $(this).data('pre'); }).data('pre', $selectStatus.val());` – Capy Oct 31 '14 at 15:51
  • I was thinking where will I use jQuery.data() method, and here is the answer – open and free Apr 17 '15 at 11:30
  • 2
    @Sinaesthetic this line sets one value to all the "mySelect" elements `$('mySelect').data('pre', $(this).val());` It should be as : `$('mySelect').each(function() { $(this).data('pre', $(this).val()); });` I don't have enough reputation to edit the answer :/ – Abderrahim Apr 18 '17 at 17:00
10

Track the value by hand.

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;
  });
});
August Lilleaas
  • 51,168
  • 11
  • 94
  • 107
  • I cannot use the above approach beacuse i am having multiple select boxes in that same page with whom i have to deal. – Alpesh Nov 02 '10 at 10:33
  • 1
    You said nothing about multiple select buttons in your question. Updated my answer to support multiple boxes though. – August Lilleaas Nov 02 '10 at 10:37
  • 1
    best answer. I think this solution is better than usign focus() and change() 'cause it relies on jquery for browser compatibility raither then the correct flow ef execution of both methods – coorasse Jun 24 '12 at 15:35
  • @coorasse: the correct flow of execution could never be any different. A select boxes value could never be changed by the user *before* the element takes focus. That being said, there's nothing wrong with this approach either :-) – Andy E Feb 11 '13 at 14:49
  • From a standpoint of 'closure' usage, i am not sure if this is better than the 'focus' solution. – James Poulose Feb 18 '13 at 23:01
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());
});
cs95
  • 274,032
  • 76
  • 480
  • 537
free4ride
  • 1,543
  • 1
  • 16
  • 21
3

I am using event "live", my solution is basically similiar with Dimitiar, but instead of using "focus", my previous value is stored when "click" is triggered.

var previous = "initial prev value";
$("select").live('click', function () {
        //update previous value
        previous = $(this).val();
    }).change(function() {
        alert(previous); //I have previous value 
    });
  • 2
    I wouldn't use this. What if the user 'tabs' into the select element and uses his keyboard arrows to select a different option? – Christian Lundahl Apr 20 '15 at 13:03
  • @Perplexor yes, it won't work with keys, otherwise it will store each values every time you press the key. This only assume the user click the drop down menu. The problem is 'live' event won't work with 'focus', I don't know any better solution. – Cica Gustiani May 01 '15 at 00:20
  • You could store the current value on focus into a separate variable. This is just from the top of my head so I'm not sure if this is ideal. – Christian Lundahl May 01 '15 at 15:49
  • If 'focus' can work with 'live' event it will be perfect. But if you dynamically create those drop down menus, you can only use 'live', that's what I know. The 'focus' on 'live' doesn't trigger the event to store the new values, unfortunately, but I don't know with the new jquery – Cica Gustiani May 01 '15 at 22:01
  • live is dead in the new versions of jQuery! [http://stackoverflow.com/questions/14354040/jquery-1-9-live-is-not-a-function] – remo Mar 15 '16 at 20:47
2

keep the currently selected drop down value with chosen jquery in a global variable before writing the drop down 'on change' action function. If you want to set previous value in the function you can use the global variable.

//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;
         }
  });
});
Deshani Tharaka
  • 173
  • 3
  • 12
2

There are several ways to achieve your desired result, this my humble way of doing it:

Let the element hold its previous value, so add an attribute 'previousValue'.

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

Once initialized, 'previousValue' could now be used as an attribute. In JS, to access the previousValue of this select:

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

After you are done using 'previousValue', update the attribute to current value.

1

How about using a custom jQuery event with an angular watch type interface;

// 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
});
Nick M
  • 1,542
  • 13
  • 17
1

I know this is an old thread, but thought I may add on a little extra. In my case I was wanting to pass on the text, val and some other data attr. In this case its better to store the whole option as a prev value rather than just the val.

Example code below:

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

EDIT:

I forgot to add .clone() onto the element. in not doing so when you try to pull back the values you end up pulling in the new copy of the select rather than the previous. Using the clone() method stores a copy of the select instead of an instance of it.

JBW
  • 53
  • 5
  • Hi, I tried your solution and things work the first time I change the dropdown value. However, the previous value is never reset so I keep getting the same previous value and text results. – kamilah carlisle Apr 21 '21 at 17:37
0

Use following code,I have tested it and its working

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;
            }
});
Er.KT
  • 2,714
  • 1
  • 28
  • 66
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();
})();
Bilal
  • 419
  • 1
  • 3
  • 11
0

I'd like to contribute another option to solve this issue; since the solutions proposed above did not solve my 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());
        }
      );
    }
)();

This does use jQuery so that def. is a dependency here, but this can be adapted to work in pure javascript. (Add a listener to the body, check if the original target was a select, execute function, ...).

By attaching the change listener to the body, you can pretty much be sure this will fire after specific listeners for the selects, otherwise the value of 'data-previous' will be overwritten before you can even read it.

This is of course assuming that you prefer to use separate listeners for your set-previous and check-value. It fits right in with the single-responsibility pattern.

Note: This adds this 'previous' functionality to all selects, so be sure to fine-tune the selectors if needed.

thisisboris
  • 433
  • 1
  • 3
  • 13
0

Well, why don't you store the current selected value, and when the selected item is changed you will have the old value stored? (and you can update it again as you wish)

Soufiane Hassou
  • 15,973
  • 2
  • 36
  • 71
  • Well i cannot do that because in my case i am having multiple select boxes in that same page. And saving initial value of all at the beginning will be too teadious. – Alpesh Nov 02 '10 at 10:36
0

This is an improvement on @thisisboris answer. It adds a current value to data, so the code can control when a variable set to the current value is changed.

(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() );
        }
    );
})();
ermSO
  • 195
  • 1
  • 1
  • 11
0

Best 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);
});
ViES
  • 311
  • 2
  • 11
  • 1
    this answer is based on the "Selectric" js library, and not on 'plain' jQuery or javascript. Eventhough is the best, it doesnt suit the original question nor does it say that the user needs to install something else for it to work – gadget00 Oct 24 '18 at 16:58
0

I needed to reveal a different div based on the selection

This is how you can do it with jquery and es6 syntax

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()
        }
    })
})
Dieter Gribnitz
  • 4,143
  • 2
  • 36
  • 36
0

var last_value;
var current_value;
$(document).on("click","select",function(){
    last_value = $(this).val();
}).on("change","select",function(){
    current_value = $(this).val();

    console.log('last value - '+last_value);
    console.log('current value - '+current_value);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select name="test">
<option value="stack">Stack</option>
<option value="overflow">Overflow</option>
<option value="my">My</option>
<option value="question">Question</option>
</select>
  • You should not post code only answers. Please consider editing the question to include a description about the solution. This provides more benefit to users. – Derek C. Sep 16 '20 at 15:27