314

I have a hidden text field whose value gets updated via an AJAX response.

<input type="hidden" value="" name="userid" id="useid" />

When this value changes, I would like to fire an AJAX request. Can anyone advise on how to detect the change?

I have the following code, but do not know how to look for the value:

$('#userid').change( function() {  
    alert('Change!'); 
}) 
Damjan Pavlica
  • 31,277
  • 10
  • 71
  • 76
Ben
  • 6,026
  • 11
  • 51
  • 72
  • 2
    If it gets updated via an ajax response, why don't you just fire the new ajax request in the success function of the response? – BonyT Jun 30 '11 at 10:02
  • 2
    $('#userid').val() will give you the value if that's what you're asking – BonyT Jun 30 '11 at 10:03
  • UPDATE: a change event is now triggered when the value of a hidden field is updated. – Steven May 04 '16 at 21:58

9 Answers9

693

So this is way late, but I've discovered an answer, in case it becomes useful to anyone who comes across this thread.

Changes in value to hidden elements don't automatically fire the .change() event. So, wherever it is that you're setting that value, you also have to tell jQuery to trigger it.

function setUserID(myValue) {
     $('#userid').val(myValue)
                 .trigger('change');
}

Once that's the case,

$('#userid').change(function(){
      //fire your ajax call  
})

should work as expected.

yycroman
  • 7,511
  • 1
  • 19
  • 21
  • 5
    Is `.trigger()` generally better to use over just calling `change()`? – Hanna Apr 23 '13 at 23:15
  • 1
    It works, but it seems like it triggers the change event twice!. Is like if I put this code, it treggers it twice, if I remove the code, no triggers w/e.!! – Janx from Venezuela Aug 13 '13 at 22:02
  • 1
    To make it behaves the same as `change` event you should add the code in `setUserID()` to check whether the the value is really change or not. ```if ($('#userid').val() != myVaule) { // set val() and trigger change }``` – nnattawat Nov 19 '15 at 00:37
  • 2
    This is especially useful if you are are trying to catch a "change" event that as being changed via javascript, otherwise the changes made by javascript cannot be caught by the .change(handler) or .on("change", handler) – JJK Sep 09 '16 at 21:06
  • 11
    so If I don't have control on the function that changes the value of the hidden field (i.e. can't fire the trigger), this solution wont work , right ? – osama yaccoub Oct 09 '16 at 11:24
55

Since hidden input does not trigger "change" event on change, I used MutationObserver to trigger this instead.

(Sometimes hidden input value changes are done by some other scripts you can't modify)

This does not work in IE10 and below

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var trackChange = function(element) {
  var observer = new MutationObserver(function(mutations, observer) {
    if(mutations[0].attributeName == "value") {
        $(element).trigger("change");
    }
  });
  observer.observe(element, {
    attributes: true
  });
}

// Just pass an element to the function to start tracking
trackChange( $("input[name=foo]")[0] );
lulalala
  • 17,572
  • 15
  • 110
  • 169
  • AFAIK the mutationobserver also does NOT get fired on a change inside a text field (no matter if hidden or not) – Ole Albers Jan 19 '17 at 20:41
  • 4
    Works great! @OleAlbers - OP asked about `input[type=hidden]` – Shay Apr 10 '17 at 00:06
  • 1
    I've used this in combination with a function that was using the map command of jquery to retrieve a collection of hidden input field values. Thanks so much @lulalala! – AdamJones May 02 '17 at 14:54
  • 2
    Simple and easy to understand. This solution, as opposed to the "you must trigger the event when you change the value" solutions, does not rely on the programmer having access to the code at the point where the value is changed, making it more useful as long as you don't have to support a version older than IE11. It worked great for me. Thanks – Joe Salazar Feb 21 '18 at 13:15
  • Great solution! Thank you! For some reason the `trigger('change')` didn't work for me, so I've created a CustomEvent, registered it and then `element.dispatchEvent(myCustomEvent)` – Tanase Butcaru Oct 24 '18 at 16:57
  • This is also great for Chrome Extensions where a content script needs to react to a hidden field change. – Volomike Sep 16 '20 at 23:00
9

You can simply use the below function, You can also change the type element.

 $("input[type=hidden]").bind("change", function() {
       alert($(this).val()); 
 });

Changes in value to hidden elements don't automatically fire the .change() event. So, wherever it is that you're setting that value, you also have to tell jQuery to trigger it.

HTML

 <div id="message"></div>
<input type="hidden" id="testChange" value="0"  />    

JAVASCRIPT

var $message = $('#message');
var $testChange = $('#testChange');
var i = 1;

function updateChange() {
    $message.html($message.html() + '<p>Changed to ' + $testChange.val() + '</p>');
}

$testChange.on('change', updateChange);

setInterval(function() {
    $testChange.val(++i).trigger('change');; 
    console.log("value changed" +$testChange.val());
}, 3000);

updateChange();

should work as expected.

http://jsfiddle.net/7CM6k/3/

Tarun Gupta
  • 6,305
  • 2
  • 42
  • 39
  • 1
    Not working for me... Anyway, how could it be possible to paste value into an Hidden Field? :/ – Simon Dugré Jul 18 '14 at 19:45
  • Hey Thanks, paste should not be there, but change can detect the hidden field change event – Tarun Gupta Jul 19 '14 at 04:15
  • @KrisErickson Thanks for the fiddle, I have updated the code so that it can detect the change explicitly, Please follow the updated fiddle http://jsfiddle.net/7CM6k/3/ – Tarun Gupta Aug 01 '14 at 05:18
  • 1
    @TarunGupta yeah it's working on the trigger, but not changing the value. Browsers don't fire the change event when a hidden has its value changed, you have to do it manually. – Kris Erickson Aug 01 '14 at 14:59
  • The first part of this answer about the binding to all hidden fields was very helpful. Thanks! – Chad Feb 04 '15 at 20:20
  • "*Changes in value to hidden elements don't automatically fire the .change() event. So, wherever it is that you're setting that value, you also have to tell jQuery to trigger it.*" Hrm. [That text](http://stackoverflow.com/revisions/24797515/3) seems [awfully familiar](http://stackoverflow.com/a/8965804/1028230). – ruffin Jan 04 '16 at 22:33
7
$('#userid').change(function(){
  //fire your ajax call  
});

$('#userid').val(10).change();
Digambar Patil
  • 128
  • 2
  • 3
5

Building off of Viktar's answer, here's an implementation you can call once on a given hidden input element to ensure that subsequent change events get fired whenever the value of the input element changes:

/**
 * Modifies the provided hidden input so value changes to trigger events.
 *
 * After this method is called, any changes to the 'value' property of the
 * specified input will trigger a 'change' event, just like would happen
 * if the input was a text field.
 *
 * As explained in the following SO post, hidden inputs don't normally
 * trigger on-change events because the 'blur' event is responsible for
 * triggering a change event, and hidden inputs aren't focusable by virtue
 * of being hidden elements:
 * https://stackoverflow.com/a/17695525/4342230
 *
 * @param {HTMLInputElement} inputElement
 *   The DOM element for the hidden input element.
 */
function setupHiddenInputChangeListener(inputElement) {
  const propertyName = 'value';

  const {get: originalGetter, set: originalSetter} =
    findPropertyDescriptor(inputElement, propertyName);

  // We wrap this in a function factory to bind the getter and setter values
  // so later callbacks refer to the correct object, in case we use this
  // method on more than one hidden input element.
  const newPropertyDescriptor = ((_originalGetter, _originalSetter) => {
    return {
      set: function(value) {
        const currentValue = originalGetter.call(inputElement);

        // Delegate the call to the original property setter
        _originalSetter.call(inputElement, value);

        // Only fire change if the value actually changed.
        if (currentValue !== value) {
          inputElement.dispatchEvent(new Event('change'));
        }
      },

      get: function() {
        // Delegate the call to the original property getter
        return _originalGetter.call(inputElement);
      }
    }
  })(originalGetter, originalSetter);

  Object.defineProperty(inputElement, propertyName, newPropertyDescriptor);
};

/**
 * Search the inheritance tree of an object for a property descriptor.
 *
 * The property descriptor defined nearest in the inheritance hierarchy to
 * the class of the given object is returned first.
 *
 * Credit for this approach:
 * https://stackoverflow.com/a/38802602/4342230
 *
 * @param {Object} object
 * @param {String} propertyName
 *   The name of the property for which a descriptor is desired.
 *
 * @returns {PropertyDescriptor, null}
 */
function findPropertyDescriptor(object, propertyName) {
  if (object === null) {
    return null;
  }

  if (object.hasOwnProperty(propertyName)) {
    return Object.getOwnPropertyDescriptor(object, propertyName);
  }
  else {
    const parentClass = Object.getPrototypeOf(object);

    return findPropertyDescriptor(parentClass, propertyName);
  }
}

Call this on document ready like so:

$(document).ready(function() {
  setupHiddenInputChangeListener($('myinput')[0]);
});
GuyPaddock
  • 2,233
  • 2
  • 23
  • 27
4

It is possible to use Object.defineProperty() in order to redefine the 'value' property of the input element and do anything during its changing.

Object.defineProperty() allows us to define a getter and setter for a property, thus controlling it.

replaceWithWrapper($("#hid1")[0], "value", function(obj, property, value) { 
  console.log("new value:", value)
});

function replaceWithWrapper(obj, property, callback) {
  Object.defineProperty(obj, property, new function() {
    var _value = obj[property];
    return {
      set: function(value) {
        _value = value;
        callback(obj, property, value)
      },
      get: function() {
        return _value;
      }
    }
  });
}

$("#hid1").val(4);

https://jsfiddle.net/bvvmhvfk/

  • 2
    I like this approach, especially because everyone else's answer is "trigger the change yourself" ... which is not always feasible. – sMyles Oct 07 '17 at 00:35
  • 1
    this is almost working for me, everything but the final value in the hidden field isn't actually being changed, if you check the jsfiddle the hidden field value doesn't change from '123' (using Chrome) – MetaGuru Mar 13 '18 at 15:38
  • Very close, but as the others have mentioned it doesn't maintain a reference to the original mutator/setter for the field, so updates fail to affect the hidden input itself. I'm posting a new solution that incorporates pieces of this approach and the one from https://stackoverflow.com/a/38802602/4342230 – GuyPaddock Nov 26 '19 at 17:42
3

I started with Vikars answer, but noticed too that when the hidden form fields used in a HTML form that the last changes didn't get submited. Later on I found Thomas answer, so I combined both to the following solution, which seems to work nicely for my hidden form fields also on submit:

   function replaceWithWrapper(selector, property, callback) {
      function findDescriptor(obj, prop){
         if (obj != null){
            return Object.hasOwnProperty.call(obj, prop)?
               Object.getOwnPropertyDescriptor(obj, prop):
               findDescriptor(Object.getPrototypeOf(obj), prop);
         }
      }

      jQuery(selector).each(function(idx, obj) {
         var {get, set} = findDescriptor(obj, property);

         Object.defineProperty(obj, property, {
            configurable: true,
            enumerable: true,

            get() { //overwrite getter
               var v = get.call(this);  //call the original getter
               //console.log("get '+property+':", v, this);
               return v;
            },
            
            set(v) { //same for setter
               //console.log("set '+property+':", v, this);
               set.call(this, v);
               callback(obj, property, v)
            }
         });
      });
   }

   replaceWithWrapper('#myhiddenfield', 'value', function() {
      console.log('myhiddenfield value changed!');
   });
hwde
  • 353
  • 2
  • 6
0

This example returns the draft field value every time the hidden draft field changes its value (chrome browser):

var h = document.querySelectorAll('input[type="hidden"][name="draft"]')[0];
//or jquery.....
//var h = $('input[type="hidden"][name="draft"]')[0];

observeDOM(h, 'n', function(draftValue){ 
  console.log('dom changed draftValue:'+draftValue);
});


var observeDOM = (function(){
var MutationObserver = window.MutationObserver || 
window.WebKitMutationObserver;

  return function(obj, thistime, callback){
    if(typeof obj === 'undefined'){
      console.log('obj is undefined');
      return;
    }

    if( MutationObserver ){

        // define a new observer
        var obs = new MutationObserver(function(mutations, observer){

            if( mutations[0].addedNodes.length || mutations[0].removedNodes.length ){

               callback('pass other observations back...');

            }else if(mutations[0].attributeName == "value" ){

               // use callback to pass back value of hidden form field                            
               callback( obj.value );

            }

        });

        // have the observer observe obj for changes in children
        // note 'attributes:true' else we can't read the input attribute value
        obs.observe( obj, { childList:true, subtree:true, attributes:true  });

       }
  };
})();
user2677034
  • 624
  • 10
  • 20
-5

Although this thread is 3 years old, here is my solution:

$(function ()
{
    keep_fields_uptodate();
});

function keep_fields_uptodate()
{
    // Keep all fields up to date!
    var $inputDate = $("input[type='date']");
    $inputDate.blur(function(event)
    {
        $("input").trigger("change");
    });
}
mdbxz
  • 189
  • 2
  • 11
  • 4
    the blur event is triggered only when the input lose the focus. Is not a valid response for a hidden input – manuerumx Nov 11 '15 at 18:45