jQuery - Mendeteksi perubahan nilai pada bidang input tersembunyi

270

Saya memiliki bidang teks tersembunyi yang nilainya diperbarui melalui respons AJAX.

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

Ketika nilai ini berubah, saya ingin memecat permintaan AJAX. Adakah yang bisa menyarankan cara mendeteksi perubahan?

Saya memiliki kode berikut, tetapi tidak tahu bagaimana mencari nilainya:

$('#userid').change( function() {  
    alert('Change!'); 
}) 
Ben
sumber
2
Jika itu diperbarui melalui respons ajax, mengapa Anda tidak memecat permintaan ajax baru dalam fungsi keberhasilan respons?
BonyT
2
$ ('# userid'). val () akan memberi Anda nilai jika itu yang Anda minta
BonyT
PEMBARUAN: peristiwa perubahan sekarang dipicu ketika nilai bidang tersembunyi diperbarui.
Steven

Jawaban:

622

Jadi ini sangat terlambat, tetapi saya telah menemukan jawaban, kalau-kalau ini berguna bagi siapa saja yang menemukan utas ini.

Perubahan nilai pada elemen tersembunyi tidak secara otomatis mem-flash event .change (). Jadi, di mana pun Anda menetapkan nilai itu, Anda juga harus memberi tahu jQuery untuk memicunya.

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

Begitu itu terjadi,

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

harus bekerja seperti yang diharapkan.

yycroman
sumber
5
Apakah .trigger()umumnya lebih baik digunakan daripada sekadar menelepon change()?
Hanna
1
Ini berfungsi, tetapi sepertinya itu memicu perubahan acara dua kali !. Seperti jika saya meletakkan kode ini, ini akan mengaktifkannya dua kali, jika saya menghapus kode, tidak ada pemicu w / e. !!
Janx dari Venezuela
1
Untuk membuatnya berperilaku sama dengan changeacara Anda harus menambahkan kode setUserID()untuk memeriksa apakah nilainya benar-benar berubah atau tidak. if ($('#userid').val() != myVaule) { // set val() and trigger change }
nnattawat
1
Ini sangat berguna jika Anda mencoba menangkap peristiwa "perubahan" yang seperti diubah melalui javascript, jika tidak, perubahan yang dibuat oleh javascript tidak dapat ditangkap oleh .change (handler) atau .on ("change", handler)
JJK
7
jadi jika saya tidak memiliki kontrol pada fungsi yang mengubah nilai bidang tersembunyi (yaitu tidak dapat memicu pemicu), solusi ini tidak akan berfungsi, kan?
osama yaccoub
31

Karena input tersembunyi tidak memicu peristiwa "perubahan" pada perubahan, saya menggunakan MutationObserver untuk memicu ini sebagai gantinya.

(Terkadang perubahan nilai input tersembunyi dilakukan oleh beberapa skrip lain yang tidak dapat Anda modifikasi)

Ini tidak berfungsi di IE10 dan di bawah

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] );
lalalala
sumber
AFAIK the mutationobserver juga TIDAK dipecat karena perubahan di dalam bidang teks (tidak peduli apakah tersembunyi atau tidak)
Ole Albers
3
Bagus sekali! @OleAlbers - OP bertanya tentanginput[type=hidden]
Shay
1
Saya telah menggunakan ini dalam kombinasi dengan fungsi yang menggunakan perintah peta jquery untuk mengambil koleksi nilai bidang input tersembunyi. Terima kasih banyak @lulalala!
AdamJones
2
Sederhana dan mudah dimengerti. Solusi ini, tidak seperti solusi "Anda harus memicu peristiwa ketika Anda mengubah nilai", tidak bergantung pada programmer yang memiliki akses ke kode pada titik di mana nilai tersebut diubah, membuatnya lebih berguna selama Anda tidak harus mendukung versi yang lebih lama dari IE11. Ini bekerja sangat baik untuk saya. Terima kasih
Joe Salazar
Solusi bagus! Terima kasih! Untuk beberapa alasan trigger('change')itu tidak berhasil untuk saya, jadi saya telah membuat CustomEvent, mendaftarkannya dan kemudianelement.dispatchEvent(myCustomEvent)
tbutcaru
8

Anda cukup menggunakan fungsi di bawah ini, Anda juga dapat mengubah elemen tipe.

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

Perubahan nilai pada elemen tersembunyi tidak secara otomatis mem-flash event .change (). Jadi, di mana pun Anda menetapkan nilai itu, Anda juga harus memberi tahu jQuery untuk memicunya.

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

harus bekerja seperti yang diharapkan.

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

Tarun Gupta
sumber
1
Tidak berfungsi untuk saya ... Pokoknya, bagaimana mungkin untuk menempelkan nilai ke dalam Bidang Tersembunyi? : /
Simon Dugré
Hai, terima kasih, tempel seharusnya tidak ada di sana, tetapi perubahan dapat mendeteksi acara perubahan bidang yang tersembunyi
Tarun Gupta
@KrisErickson Terima kasih untuk biola, saya telah memperbarui kode sehingga dapat mendeteksi perubahan secara eksplisit, Silakan ikuti biola yang diperbarui jsfiddle.net/7CM6k/3
Tarun Gupta
1
@ TalunGupta ya itu bekerja pada pelatuk, tetapi tidak mengubah nilainya. Peramban tidak memecat acara perubahan ketika nilai tersembunyi berubah, Anda harus melakukannya secara manual.
Kris Erickson
Bagian pertama dari jawaban ini tentang pengikatan ke semua bidang tersembunyi sangat membantu. Terima kasih!
Chad
6
$('#userid').change(function(){
  //fire your ajax call  
});

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

Dimungkinkan untuk menggunakan Object.defineProperty()untuk mendefinisikan kembali properti 'nilai' dari elemen input dan melakukan apa pun selama perubahan.

Object.defineProperty() memungkinkan kita untuk mendefinisikan pengambil dan penyetel untuk properti, dengan demikian mengendalikannya.

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
sumber
1
Saya suka pendekatan ini, terutama karena jawaban orang lain adalah "memicu perubahan sendiri" ... yang tidak selalu layak.
sMyles
1
ini hampir berhasil bagi saya, semuanya kecuali nilai akhir di bidang tersembunyi sebenarnya tidak diubah, jika Anda memeriksa jsfiddle nilai bidang tersembunyi tidak berubah dari '123' (menggunakan Chrome)
MetaGuru
Sangat dekat, tetapi seperti yang lain telah disebutkan itu tidak mempertahankan referensi ke mutator / setter asli untuk bidang, sehingga pembaruan gagal mempengaruhi input tersembunyi itu sendiri. Saya memposting solusi baru yang menggabungkan potongan-potongan dari pendekatan ini dan yang dari stackoverflow.com/a/38802602/4342230
GuyPaddock
0

Contoh ini mengembalikan nilai bidang konsep setiap kali bidang konsep tersembunyi mengubah nilainya (browser 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  });

       }
  };
})();
pengguna2677034
sumber
0

Membangun dari jawaban Viktar , berikut ini adalah implementasi yang dapat Anda panggil sekali pada elemen input tersembunyi yang diberikan untuk memastikan bahwa acara perubahan berikutnya dipecat setiap kali nilai elemen input berubah:

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

Sebut ini pada dokumen siap seperti:

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

Meskipun utas ini berusia 3 tahun, inilah solusi saya:

$(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
sumber
3
acara blur dipicu hanya ketika input kehilangan fokus. Bukan respons yang valid untuk input tersembunyi
manuerumx