jQuery - Détecter les changements de valeur sur un champ de saisie caché

270

J'ai un champ de texte caché dont la valeur est mise à jour via une réponse AJAX.

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

Lorsque cette valeur change, je voudrais déclencher une demande AJAX. Quelqu'un peut-il nous conseiller sur la façon de détecter le changement?

J'ai le code suivant, mais je ne sais pas comment rechercher la valeur:

$('#userid').change( function() {  
    alert('Change!'); 
}) 
Ben
la source
2
S'il est mis à jour via une réponse ajax, pourquoi ne pas simplement lancer la nouvelle demande ajax dans la fonction de réussite de la réponse?
BonyT
2
$ ('# userid'). val () vous donnera la valeur si c'est ce que vous demandez
BonyT
UPDATE: un événement de modification est maintenant déclenché lorsque la valeur d'un champ caché est mise à jour.
Steven

Réponses:

622

C'est donc beaucoup trop tard, mais j'ai découvert une réponse, au cas où cela deviendrait utile à quiconque rencontre ce fil.

Les changements de valeur en éléments cachés ne déclenchent pas automatiquement l'événement .change (). Donc, où que vous définissiez cette valeur, vous devez également dire à jQuery de la déclencher.

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

Une fois que c'est le cas,

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

devrait fonctionner comme prévu.

yycroman
la source
5
Est-il .trigger()généralement préférable d'utiliser plutôt que d'appeler change()?
Hanna
1
Cela fonctionne, mais il semble qu'il déclenche l'événement de changement deux fois!. C'est comme si je mettais ce code, il le tégresse deux fois, si je supprime le code, pas de déclencheur w / e. !!
Janx du Venezuela
1
Pour qu'il se comporte comme un changeévénement, vous devez ajouter le code setUserID()pour vérifier si la valeur est vraiment modifiée ou non. if ($('#userid').val() != myVaule) { // set val() and trigger change }
nnattawat
1
Ceci est particulièrement utile si vous essayez d'attraper un événement "change" qui est modifié via javascript, sinon les modifications apportées par javascript ne peuvent pas être interceptées par .change (handler) ou .on ("change", handler)
JJK
7
donc si je n'ai pas le contrôle sur la fonction qui change la valeur du champ caché (ie ne peut pas déclencher le déclencheur), cette solution ne fonctionnera pas, non?
osama yaccoub
31

Étant donné que l'entrée masquée ne déclenche pas d'événement «changement» lors d'un changement, j'ai utilisé MutationObserver pour déclencher cela à la place.

(Parfois, les changements de valeur d'entrée cachés sont effectués par d'autres scripts que vous ne pouvez pas modifier)

Cela ne fonctionne pas dans IE10 et ci-dessous

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
la source
AFAIK le mutationobserver ne se fait PAS tirer non plus sur un changement à l'intérieur d'un champ de texte (qu'il soit caché ou non)
Ole Albers
3
Fonctionne très bien! @OleAlbers - OP a posé des questions surinput[type=hidden]
Shay
1
Je l'ai utilisé en combinaison avec une fonction qui utilisait la commande map de jquery pour récupérer une collection de valeurs de champ de saisie masquées. Merci beaucoup @lulalala!
AdamJones
2
Simple et facile à comprendre. Cette solution, contrairement aux solutions "vous devez déclencher l'événement lorsque vous modifiez la valeur", ne repose pas sur le programmeur ayant accès au code au point où la valeur est modifiée, ce qui le rend plus utile tant que vous ne pas besoin de prendre en charge une version antérieure à IE11. Cela a très bien fonctionné pour moi. Merci
Joe Salazar
Excellente solution! Je vous remercie! Pour une raison quelconque, cela trigger('change')n'a pas fonctionné pour moi, j'ai donc créé un événement personnalisé, l'ai enregistré, puiselement.dispatchEvent(myCustomEvent)
tbutcaru
8

Vous pouvez simplement utiliser la fonction ci-dessous, vous pouvez également changer l'élément type.

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

Les changements de valeur en éléments cachés ne déclenchent pas automatiquement l'événement .change (). Donc, où que vous définissiez cette valeur, vous devez également dire à jQuery de la déclencher.

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

devrait fonctionner comme prévu.

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

Tarun Gupta
la source
1
Ne fonctionne pas pour moi ... Quoi qu'il en soit, comment pourrait-il être possible de coller de la valeur dans un champ caché? : /
Simon Dugré
Hé merci, la pâte ne devrait pas être là, mais le changement peut détecter l'événement de changement de champ caché
Tarun Gupta
@KrisErickson Merci pour le violon, j'ai mis à jour le code afin qu'il puisse détecter le changement explicitement, veuillez suivre le violon mis à jour jsfiddle.net/7CM6k/3
Tarun Gupta
1
@TarunGupta oui, cela fonctionne sur le déclencheur, mais ne change pas la valeur. Les navigateurs ne déclenchent pas l'événement change lorsqu'un caché a sa valeur modifiée, vous devez le faire manuellement.
Kris Erickson
La première partie de cette réponse sur la liaison à tous les champs cachés a été très utile. Merci!
Chad
6
$('#userid').change(function(){
  //fire your ajax call  
});

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

Il est possible de l'utiliser Object.defineProperty()pour redéfinir la propriété 'value' de l'élément d'entrée et faire n'importe quoi lors de son changement.

Object.defineProperty() nous permet de définir un getter et un setter pour une propriété, donc de la contrôler.

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
la source
1
J'aime cette approche, surtout parce que la réponse de tout le monde est "déclenchez le changement vous-même" ... ce qui n'est pas toujours faisable.
sMyles
1
cela fonctionne presque pour moi, tout, mais la valeur finale dans le champ caché n'est pas réellement modifiée, si vous vérifiez le jsfiddle, la valeur du champ caché ne change pas de '123' (en utilisant Chrome)
MetaGuru
Très proche, mais comme les autres l'ont mentionné, il ne conserve pas de référence au mutateur / setter d'origine pour le champ, donc les mises à jour n'affectent pas l'entrée masquée elle-même. Je poste une nouvelle solution qui intègre des éléments de cette approche et celle de stackoverflow.com/a/38802602/4342230
GuyPaddock
0

Cet exemple renvoie la valeur du champ brouillon à chaque fois que le champ brouillon masqué change de valeur (navigateur 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  });

       }
  };
})();
user2677034
la source
0

À partir de la réponse de Viktar , voici une implémentation que vous pouvez appeler une fois sur un élément d'entrée caché donné pour vous assurer que l'événement de changement suivant est déclenché chaque fois que la valeur de l'élément d'entrée change:

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

Appelez cela sur un document prêt comme ceci:

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

Bien que ce fil ait 3 ans, voici ma 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
la source
3
l'événement flou est déclenché uniquement lorsque l'entrée perd le focus. N'est pas une réponse valide pour une entrée cachée
manuerumx