jQuery - Detecta el cambio de valor en el campo de entrada oculto

270

Tengo un campo de texto oculto cuyo valor se actualiza a través de una respuesta AJAX.

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

Cuando este valor cambia, me gustaría disparar una solicitud AJAX. ¿Alguien puede aconsejar sobre cómo detectar el cambio?

Tengo el siguiente código, pero no sé cómo buscar el valor:

$('#userid').change( function() {  
    alert('Change!'); 
}) 
Ben
fuente
2
Si se actualiza a través de una respuesta ajax, ¿por qué no disparas la nueva solicitud ajax en la función de éxito de la respuesta?
BonyT
2
$ ('# userid'). val () le dará el valor si eso es lo que está pidiendo
BonyT
ACTUALIZACIÓN: ahora se activa un evento de cambio cuando se actualiza el valor de un campo oculto.
Steven

Respuestas:

622

Así que esto es demasiado tarde, pero he descubierto una respuesta, en caso de que sea útil para cualquiera que se encuentre con este hilo.

Los cambios en el valor de los elementos ocultos no activan automáticamente el evento .change (). Entonces, donde sea que esté estableciendo ese valor, también debe decirle a jQuery que lo active.

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

Una vez que ese sea el caso,

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

Debería funcionar como se esperaba.

yycroman
fuente
55
¿Es .trigger()generalmente mejor usarlo solo con solo llamar change()?
Hanna
1
Funciona, pero parece que desencadena el evento de cambio dos veces. Es como si pongo este código, lo activa dos veces, si elimino el código, ¡¡no hay activadores w / e !!
Janx de Venezuela
1
Para que se comporte igual que un changeevento, debe agregar el código setUserID()para verificar si el valor realmente cambia o no. if ($('#userid').val() != myVaule) { // set val() and trigger change }
nnattawat
1
Esto es especialmente útil si está tratando de detectar un evento de "cambio" que se modifica a través de JavaScript, de lo contrario los cambios realizados por JavaScript no pueden ser detectados por .change (handler) o .on ("change", handler)
JJK
77
Entonces, si no tengo control sobre la función que cambia el valor del campo oculto (es decir, no puedo disparar el disparador), esta solución no funcionará, ¿verdad?
osama yaccoub
31

Como la entrada oculta no activa el evento "change" en el cambio, utilicé MutationObserver para activar esto.

(A veces, algunos otros scripts que no puede modificar modifican los valores de entrada ocultos)

Esto no funciona en IE10 y versiones inferiores

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
fuente
AFAIK the mutationobserver tampoco se dispara en un cambio dentro de un campo de texto (no importa si está oculto o no)
Ole Albers
3
¡Funciona genial! @OleAlbers - OP preguntó sobreinput[type=hidden]
Shay
1
He usado esto en combinación con una función que estaba usando el comando map de jquery para recuperar una colección de valores de campo de entrada ocultos. Muchas gracias @lulalala!
AdamJones
2
Simple y fácil de entender. Esta solución, a diferencia de las soluciones "debe activar el evento cuando cambia el valor", no se basa en que el programador tenga acceso al código en el punto donde se cambia el valor, lo que lo hace más útil siempre que no lo haga. No tiene que admitir una versión anterior a IE11. Funciono muy bien para mi. Gracias
Joe Salazar
Gran solución! ¡Gracias! Por alguna razón trigger('change'), no funcionó para mí, así que creé un CustomEvent, lo registré y luegoelement.dispatchEvent(myCustomEvent)
tbutcaru, el
8

Simplemente puede usar la siguiente función, También puede cambiar el elemento de tipo.

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

Los cambios en el valor de los elementos ocultos no activan automáticamente el evento .change (). Entonces, donde sea que esté estableciendo ese valor, también debe decirle a jQuery que lo active.

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

Debería funcionar como se esperaba.

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

Tarun Gupta
fuente
1
No funciona para mí ... De todos modos, ¿cómo podría ser posible pegar valor en un campo oculto? : /
Simon Dugré
Hola, gracias, pegar no debería estar allí, pero el cambio puede detectar el evento de cambio de campo oculto
Tarun Gupta
@KrisErickson Gracias por el violín, he actualizado el código para que pueda detectar el cambio explícitamente. Siga el violín actualizado jsfiddle.net/7CM6k/3
Tarun Gupta
1
@TarunGupta, sí, está trabajando en el disparador, pero no está cambiando el valor. Los navegadores no activan el evento de cambio cuando un valor oculto tiene un valor cambiado, debe hacerlo manualmente.
Kris Erickson
La primera parte de esta respuesta sobre el enlace a todos los campos ocultos fue muy útil. ¡Gracias!
Chad
6
$('#userid').change(function(){
  //fire your ajax call  
});

$('#userid').val(10).change();
Digambar Patil
fuente
4

Es posible usarlo Object.defineProperty()para redefinir la propiedad 'value' del elemento de entrada y hacer cualquier cosa durante su cambio.

Object.defineProperty() nos permite definir un getter y setter para una propiedad, controlando así.

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/

Viktar Tserashchuk
fuente
1
Me gusta este enfoque, especialmente porque la respuesta de todos los demás es "desencadenar el cambio usted mismo" ... que no siempre es factible.
sMyles
1
esto casi funciona para mí, todo menos el valor final en el campo oculto en realidad no se está cambiando, si marca el jsfiddle, el valor del campo oculto no cambia de '123' (usando Chrome)
MetaGuru
Muy cerca, pero como los otros han mencionado, no mantiene una referencia al mutador / configurador original para el campo, por lo que las actualizaciones no afectan la entrada oculta. Estoy publicando una nueva solución que incorpora partes de este enfoque y la de stackoverflow.com/a/38802602/4342230
GuyPaddock el
0

Este ejemplo devuelve el valor del campo borrador cada vez que el campo borrador oculto cambia su valor (navegador Chrome):

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

       }
  };
})();
usuario2677034
fuente
0

A partir de la respuesta de Viktar , aquí hay una implementación que puede llamar una vez en un elemento de entrada oculto dado para garantizar que se active el evento de cambio posterior cada vez que cambie el valor del elemento de entrada:

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

Llame a esto en el documento listo así:

$(document).ready(function() {
  setupHiddenInputChangeListener($('myinput')[0]);
});
GuyPaddock
fuente
-4

Aunque este hilo tiene 3 años, aquí está mi solución:

$(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
fuente
3
el evento de desenfoque se activa solo cuando la entrada pierde el foco. No es una respuesta válida para una entrada oculta
manuerumx