jQuery - wykrywa zmianę wartości ukrytego pola wejściowego

270

Mam ukryte pole tekstowe, którego wartość jest aktualizowana za pomocą odpowiedzi AJAX.

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

Gdy ta wartość się zmienia, chciałbym uruchomić żądanie AJAX. Czy ktoś może doradzić, jak wykryć zmianę?

Mam następujący kod, ale nie wiem, jak szukać wartości:

$('#userid').change( function() {  
    alert('Change!'); 
}) 
Ben
źródło
2
Jeśli zostanie zaktualizowany za pomocą odpowiedzi ajax, dlaczego po prostu nie uruchomisz nowego żądania ajax w funkcji powodzenia odpowiedzi?
BonyT
2
$ ('# userid'). val () da ci wartość, jeśli o to pytasz
BonyT
AKTUALIZACJA: zdarzenie zmiany jest teraz wyzwalane, gdy wartość ukrytego pola jest aktualizowana.
Steven

Odpowiedzi:

622

Jest już późno, ale znalazłem odpowiedź, na wypadek, gdyby przydała się każdemu, kto natknie się na ten wątek.

Zmiany wartości ukrytych elementów nie powodują automatycznego uruchomienia zdarzenia .change (). Tak więc, gdziekolwiek ustawiasz tę wartość, musisz także powiedzieć jQuery, aby ją wyzwoliła.

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

Kiedy już tak jest,

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

powinien działać zgodnie z oczekiwaniami.

yycroman
źródło
5
Czy na .trigger()ogół lepiej jest korzystać z samego połączenia change()?
Hanna
1
Działa, ale wygląda na to, że dwukrotnie wywołuje zdarzenie zmiany! To tak, jak gdybym umieścił ten kod, przesuwa go dwa razy, jeśli usunę kod, żadnych wyzwalaczy w / e. !!
Janx z Wenezueli
1
Aby zachowywał się tak samo jak changezdarzenie, należy dodać kod, setUserID()aby sprawdzić, czy wartość naprawdę się zmienia, czy nie. if ($('#userid').val() != myVaule) { // set val() and trigger change }
nnattawat
1
Jest to szczególnie przydatne, jeśli próbujesz złapać zdarzenie „zmiany”, które jak zmienia się za pomocą javascript, w przeciwnym razie zmiany wprowadzone przez javascript nie mogą zostać przechwycone przez .change (moduł obsługi) lub .on („zmiana”, moduł obsługi)
JJK
7
więc jeśli nie mam kontroli nad funkcją, która zmienia wartość ukrytego pola (tzn. nie może uruchomić wyzwalacza), to rozwiązanie nie zadziała, prawda?
osama yaccoub
31

Ponieważ ukryte dane wejściowe nie wyzwalają zdarzenia „zmiana” przy zmianie, zamiast tego użyłem MutationObserver.

(Czasami ukrytych zmian wartości wejściowych dokonują niektóre skrypty, których nie można modyfikować)

To nie działa w IE10 i niższych wersjach

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
źródło
AFAIK serwer mutacji również NIE zostaje zwolniony przy zmianie w polu tekstowym (bez względu na to, czy jest ukryty czy nie)
Ole Albers
3
Działa świetnie! @OleAlbers - OP zapytał oinput[type=hidden]
Shay
1
Użyłem tego w połączeniu z funkcją, która używała polecenia map jquery do pobierania kolekcji ukrytych wartości pól wejściowych. Dzięki bardzo @lulalala!
AdamJones
2
Prosty i łatwy do zrozumienia. To rozwiązanie, w przeciwieństwie do rozwiązań „musisz wywołać zdarzenie przy zmianie wartości”, nie polega na tym, że programiści mają dostęp do kodu w punkcie, w którym wartość jest zmieniana, co czyni go bardziej użytecznym, dopóki nie nie będzie obsługiwał wersji starszej niż IE11. Działa mi to świetnie. Dzięki
Joe Salazar
Świetne rozwiązanie! Dziękuję Ci! Z jakiegoś powodu trigger('change')nie działało to dla mnie, więc utworzyłem CustomEvent, zarejestrowałem go, a następnieelement.dispatchEvent(myCustomEvent)
tbutcaru 24.10.2018
8

Możesz po prostu użyć poniższej funkcji, możesz także zmienić element typu.

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

Zmiany wartości ukrytych elementów nie powodują automatycznego uruchomienia zdarzenia .change (). Tak więc, gdziekolwiek ustawiasz tę wartość, musisz także powiedzieć jQuery, aby ją wyzwoliła.

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

powinien działać zgodnie z oczekiwaniami.

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

Tarun Gupta
źródło
1
Dla mnie nie działa ... W każdym razie, jak to możliwe, aby wkleić wartość do Ukrytego Pola? : /
Simon Dugré
Hej Dzięki, wklejanie nie powinno tam być, ale zmiana może wykryć zdarzenie zmiany ukrytego pola
Tarun Gupta
@KrisErickson Dzięki za skrzypce, zaktualizowałem kod, aby mógł jawnie wykryć zmianę. Postępuj zgodnie ze zaktualizowanym skrzypce jsfiddle.net/7CM6k/3
Tarun Gupta
1
@TarunGupta tak, działa na wyzwalaczu, ale nie zmienia wartości. Przeglądarki nie uruchamiają zdarzenia zmiany, gdy wartość ukryta ma zmienioną wartość, musisz to zrobić ręcznie.
Kris Erickson
Pierwsza część tej odpowiedzi na temat powiązania wszystkich ukrytych pól była bardzo pomocna. Dzięki!
Czad
6
$('#userid').change(function(){
  //fire your ajax call  
});

$('#userid').val(10).change();
Digambar Patil
źródło
4

Można go użyć Object.defineProperty()w celu ponownego zdefiniowania właściwości „value” elementu wejściowego i wykonania dowolnej czynności podczas jego zmiany.

Object.defineProperty() pozwala nam zdefiniować obiekt pobierający i ustawiający właściwość, a tym samym sterować nią.

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
źródło
1
Podoba mi się to podejście, szczególnie dlatego, że odpowiedź wszystkich innych brzmi: „samodzielnie uruchom zmianę” ... co nie zawsze jest możliwe.
sMyles,
1
to prawie działa dla mnie, wszystko oprócz ostatecznej wartości w ukrytym polu nie jest tak naprawdę zmieniane, jeśli zaznaczysz jsfiddle, wartość ukrytego pola nie zmienia się z „123” (w przeglądarce Chrome)
MetaGuru
Bardzo blisko, ale jak wspomnieli inni, nie zachowuje odniesienia do oryginalnego mutatora / settera dla pola, więc aktualizacje nie wpływają na samo ukryte wejście.
Zamieszczam
0

Ten przykład zwraca wartość pola szkicu za każdym razem, gdy ukryte pole szkicu zmienia swoją wartość (przeglądarka 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  });

       }
  };
})();
użytkownik2677034
źródło
0

Opierając się na odpowiedzi Viktara , oto implementacja, którą możesz wywołać raz na danym ukrytym elemencie wejściowym, aby upewnić się, że zdarzenie kolejnej zmiany zostanie uruchomione za każdym razem, gdy zmieni się wartość elementu wejściowego:

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

Nazwij to gotowym dokumentem w następujący sposób:

$(document).ready(function() {
  setupHiddenInputChangeListener($('myinput')[0]);
});
GuyPaddock
źródło
-4

Chociaż ten wątek ma 3 lata, oto moje rozwiązanie:

$(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
źródło
3
zdarzenie rozmycia jest wyzwalane tylko wtedy, gdy sygnał wejściowy traci ostrość. Nie jest poprawną odpowiedzią na ukryte dane wejściowe
manuerumx,