63

I have an input text in jQuery I want to know if it possible to get the value of that input text(type=number and type=text) before the onchange happens and also get the value of the same input input text after the onchange happens. This is using jQuery.

What I tried:

I tried saving the value on variable then call that value inside onchange but I am getting a blank value.

Dale K
  • 16,372
  • 12
  • 37
  • 62
Pekka
  • 935
  • 2
  • 9
  • 16
  • Please show the code you have attempted. The simplest way is to save the original value using `data()` when the element gets focus. – Gone Coding Mar 18 '15 at 09:33

9 Answers9

123

The simplest way is to save the original value using data() when the element gets focus. Here is a really basic example:

JSFiddle: http://jsfiddle.net/TrueBlueAussie/e4ovx435/

$('input').on('focusin', function(){
    console.log("Saving value " + $(this).val());
    $(this).data('val', $(this).val());
});

$('input').on('change', function(){
    var prev = $(this).data('val');
    var current = $(this).val();
    console.log("Prev value " + prev);
    console.log("New value " + current);
});

Better to use Delegated Event Handlers

Note: it is generally more efficient to use a delegated event handler when there can be multiple matching elements. This way only a single handler is added (smaller overhead and faster initialisation) and any speed difference at event time is negligible.

Here is the same example using delegated events connected to document:

$(document).on('focusin', 'input', function(){
    console.log("Saving value " + $(this).val());
    $(this).data('val', $(this).val());
}).on('change','input', function(){
    var prev = $(this).data('val');
    var current = $(this).val();
    console.log("Prev value " + prev);
    console.log("New value " + current);
});

JsFiddle: http://jsfiddle.net/TrueBlueAussie/e4ovx435/65/

Delegated events work by listening for an event (focusin, change etc) on an ancestor element (document* in this case), then applying the jQuery filter (input) to only the elements in the bubble chain then applying the function to only those matching elements that caused the event.

*Note: A a general rule, use document as the default for delegated events and not body. body has a bug, to do with styling, that can cause it to not get bubbled mouse events. Also document always exists so you can attach to it outside of a DOM ready handler :)

Gone Coding
  • 88,305
  • 23
  • 172
  • 188
  • what happens if they change the value more then once without changing focus. – bumperbox Jul 01 '17 at 05:32
  • 2
    @bumperbox: If changes while the input has focus are important to you, you should be listening for key changes and not focus/blur events – Gone Coding Jul 03 '17 at 17:29
  • 2
    Thanks, but I would suggest the name of the data is something like "prev_val", not "val", to reduce confusion. – kristianp Sep 28 '17 at 02:16
  • @kristianp: If you feel `val` is an inappropriate name for the value, please do use anything else you like. I tend to prefix them with the plugin's initials to make it unique. – Gone Coding Oct 04 '17 at 19:19
  • What if val is a file? – mashi Oct 18 '17 at 14:24
  • @mashi: It retains the local simulated file path as the value (the real file path is not available to most browsers). e.g. `C:\fakepath\test.docx`. Just change an input in the JSFiddle to `type="File"` and try it yourself. – Gone Coding Oct 18 '17 at 19:22
  • focusout will resolve if they change the value more then once without changing focus – elad silver Apr 01 '19 at 14:20
  • If you want to be able to change the select more then once without the user changing the focus, you could just add "$(this).blur();" at the end of the change event. That will force the user to change the focus after each change – MichaelJorgensenDK Mar 13 '21 at 16:15
6

Definitely you will need to store old value manually, depending on what moment you are interested (before focusing, from last change). Initial value can be taken from defaultValue property:

function onChange() {
    var oldValue = this.defaultValue;
    var newValue = this.value;
}

Value before focusing can be taken as shown in Gone Coding's answer. But you have to keep in mind that value can be changed without focusing.

mashi
  • 246
  • 2
  • 6
  • 3
    i find i consistently get 'undefined' for this.defaultValue. Mileage may vary. – Brendan Metcalfe Feb 27 '18 at 20:55
  • @Brendan: probably you've missed value attribute – mashi Mar 01 '18 at 09:06
  • 2
    I am getting undefined as well. How do I pass the defaultValue? – Cristal Apr 23 '18 at 03:25
  • 1
    The default value is the default value set to the field. Not necessarily the old value, if it was changed by the user and also "if there is no default value set, it may be undefined" - last statement hasn't been tested, just a guess. – Cybermonk Sep 16 '18 at 06:05
  • 1
    defaultValue is not defined on the jQuery object, but on the DOM. if you have a jQuery object, you can do `$jQueryObject[0]. defaultValue ` more info: https://stackoverflow.com/questions/5244466/how-safe-reliable-cross-browser-compatible-is-this0-defaultvalue – Josh Feb 19 '19 at 22:36
  • This will only work for the initial value. It wont detect the "old value" once it has been changed once – TPHughes May 14 '20 at 06:43
  • @Josh, thanks for the input. I need a solution for combo boxes, and this does not work for them. I'll try to update if I find a solution that does not rely on the value being stashed prior to the event. – Marcus Vinicius Pompeu Mar 05 '21 at 18:49
  • [UPDATE] Nope... it seems there are no simple solutions for select elements: https://stackoverflow.com/questions/4076770/getting-value-of-select-dropdown-before-change – Marcus Vinicius Pompeu Mar 05 '21 at 19:05
2

I have found a solution that works even with "Select2" plugin:

function functionName() {
  $('html').on('change', 'select.some-class', function() {
    var newValue = $(this).val();
    var oldValue = $(this).attr('data-val');
    if ( $.isNumeric(oldValue) ) { // or another condition
      // do something
    }
    $(this).attr('data-val', newValue);
  });
  $('select.some-class').trigger('change');
}
thapachaki
  • 33
  • 3
  • 8
1

I found this question today, but I'm not sure why was this made so complicated rather than implementing it simply like:

var input = $('#target');
var inputVal = input.val();
input.on('change', function() {
  console.log('Current Value: ', $(this).val());
  console.log('Old Value: ', inputVal);
  inputVal = $(this).val();
});

If you want to target multiple inputs then, use each function:

$('input').each(function() {
  var inputVal = $(this).val();
  $(this).on('change', function() {
    console.log('Current Value: ',$(this).val());
    console.log('Old Value: ', inputVal);
    inputVal = $(this).val();
});
Bhojendra Rauniyar
  • 73,156
  • 29
  • 131
  • 187
0

my solution is here

function getVal() {
    var $numInput =  $('input');
    var $inputArr = [];
    for(let i=0; i < $numInput.length ; i++ ) 
       $inputArr[$numInput[i].name] = $numInput[i].value;
    return $inputArr;
}
var $inNum =  getVal();
$('input').on('change', function() {
    // inNum is last Val
    $inNum =  getVal(); 
    // in here we update value of input
    let $val = this.value;      
});
Ehsan
  • 274
  • 5
  • 16
0

Just put the initial value into a data attribute when you create the textbox, eg

HTML

<input id="my-textbox" type="text" data-initial-value="6" value="6" /> 

JQuery

$("#my-textbox").change(function () {
 var oldValue = $(this).attr("data-initial-value");
 var newValue = $(this).val();
});
J.T. Taylor
  • 3,457
  • 1
  • 19
  • 22
0

The upvoted solution works for some situations but is not the ideal solution. The solution Bhojendra Rauniyar provided will only work in certain scenarios. The var inputVal will always remain the same, so changing the input multiple times would break the function.

The function may also break when using focus, because of the ▲▼ (up/down) spinner on html number input. That is why J.T. Taylor has the best solution. By adding a data attribute you can avoid these problems:

<input id="my-textbox" type="text" data-initial-value="6" value="6" />

0

If you only need a current value and above options don't work, you can use it this way.

$('#input').on('change', () => {
  const current = document.getElementById('input').value;
}
0

My business aim was removing classes form previous input and add it to a new one.
In this case there was simple solution: remove classes from all inputs before add

<div>
   <input type="radio" checked><b class="darkred">Value1</b>
   <input type="radio"><b>Value2</b>
   <input type="radio"><b>Value3</b>
</div>

and

$('input[type="radio"]').on('change', function () {
   var current = $(this);
   current.closest('div').find('input').each(function () {
       (this).next().removeClass('darkred')
   });
   current.next().addClass('darkred');
});

JsFiddle: http://jsfiddle.net/gkislin13/tybp8skL

Grigory Kislin
  • 12,805
  • 7
  • 98
  • 154