jQuery - ตรวจจับการเปลี่ยนแปลงค่าในช่องอินพุตที่ซ่อนอยู่


270

ฉันมีช่องข้อความที่ซ่อนอยู่ซึ่งค่าจะได้รับการปรับปรุงผ่านการตอบกลับ AJAX

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

เมื่อค่านี้เปลี่ยนแปลงฉันต้องการเริ่มการร้องขอ AJAX ทุกคนสามารถให้คำแนะนำเกี่ยวกับวิธีตรวจจับการเปลี่ยนแปลงได้หรือไม่?

ฉันมีรหัสต่อไปนี้ แต่ไม่ทราบวิธีการค้นหาค่า:

$('#userid').change( function() {  
    alert('Change!'); 
}) 

2
หากได้รับการอัพเดตผ่านการตอบกลับ ajax ทำไมคุณไม่ลองส่งคำขอ ajax ใหม่ในฟังก์ชั่นความสำเร็จของการตอบกลับ
BonyT

2
$ ('# userid'). val () จะให้คุณค่ากับคุณถ้านั่นคือสิ่งที่คุณถาม
BonyT

อัปเดต: เหตุการณ์การเปลี่ยนแปลงจะถูกเรียกใช้ในขณะนี้เมื่อมีการอัพเดทค่าของฟิลด์ที่ซ่อนอยู่
Steven

คำตอบ:


622

ดังนั้นนี่จะสายไปแล้ว แต่ฉันได้ค้นพบคำตอบในกรณีที่มันจะเป็นประโยชน์กับทุกคนที่เจอหัวข้อนี้

การเปลี่ยนแปลงมูลค่าขององค์ประกอบที่ซ่อนอยู่จะไม่ดำเนินการเหตุการณ์. change () โดยอัตโนมัติ ดังนั้นไม่ว่าคุณจะตั้งค่าที่ใดคุณก็ต้องบอกให้ jQuery เรียกใช้

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

เมื่อเป็นกรณี

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

ควรทำงานตามที่คาดไว้


5
คือ.trigger()โดยทั่วไปดีขึ้นมากกว่าที่จะใช้เพียงโทรchange()?
ฮันนา

1
มันใช้งานได้ แต่ดูเหมือนว่าจะทำให้เกิดเหตุการณ์การเปลี่ยนแปลงสองครั้ง! มันเหมือนกับว่าถ้าฉันใส่รหัสนี้มัน treggers มันสองครั้งถ้าฉันลบรหัสไม่มีทริกเกอร์ w / e. !!
Janx จากเวเนซุเอลา

1
ในการทำให้มันทำงานเหมือนกับchangeเหตุการณ์คุณควรเพิ่มโค้ดในsetUserID()เพื่อตรวจสอบว่าค่านั้นมีการเปลี่ยนแปลงจริงหรือไม่ if ($('#userid').val() != myVaule) { // set val() and trigger change }
nnattawat

1
สิ่งนี้มีประโยชน์อย่างยิ่งหากคุณพยายามจับเหตุการณ์ "เปลี่ยน" ที่ถูกเปลี่ยนผ่านทางจาวาสคริปต์มิฉะนั้นการเปลี่ยนแปลงที่ทำโดยจาวาสคริปต์จะไม่สามารถจับได้โดยการเปลี่ยนแปลง. (ตัวจัดการ) หรือ. on ("การเปลี่ยนแปลง" ตัวจัดการ)
JJK

7
ดังนั้นถ้าฉันไม่สามารถควบคุมฟังก์ชั่นที่เปลี่ยนค่าของฟิลด์ที่ซ่อนอยู่ (เช่นไม่สามารถเรียกไก) ทางออกนี้จะไม่ทำงานใช่ไหม?
osama yaccoub

31

เนื่องจากอินพุตที่ซ่อนอยู่ไม่ทำให้เกิดเหตุการณ์ "เปลี่ยน" เมื่อมีการเปลี่ยนแปลงฉันจึงใช้ MutationObserver เพื่อทริกเกอร์สิ่งนี้แทน

(บางครั้งการเปลี่ยนแปลงค่าอินพุตที่ซ่อนจะกระทำโดยสคริปต์อื่นที่คุณไม่สามารถแก้ไขได้)

สิ่งนี้ไม่ทำงานใน IE10 และด้านล่าง

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

AFAIK mutationobserver จะไม่ถูกไล่ออกจากการเปลี่ยนแปลงภายในช่องข้อความ (ไม่ว่าจะซ่อนหรือไม่ก็ตาม)
Ole Albers

3
ใช้งานได้ดี! @OleAlbers - OP ถามถึงinput[type=hidden]
Shay

1
ฉันใช้สิ่งนี้ร่วมกับฟังก์ชั่นที่ใช้คำสั่ง map ของ jquery เพื่อดึงชุดของค่าฟิลด์อินพุตที่ซ่อนอยู่ ขอบคุณมาก @lulalala!
AdamJones

2
ง่ายและเข้าใจง่าย วิธีแก้ไขนี้ตรงข้ามกับโซลูชัน "คุณต้องทริกเกอร์เหตุการณ์เมื่อคุณเปลี่ยนค่า" ไม่พึ่งพาโปรแกรมเมอร์ที่เข้าถึงรหัส ณ จุดที่มีการเปลี่ยนแปลงค่าทำให้มีประโยชน์มากขึ้นตราบใดที่คุณไม่ต้องการ ไม่จำเป็นต้องรองรับเวอร์ชันที่เก่ากว่า IE11 มันใช้งานได้ดีสำหรับฉัน ขอบคุณ
Joe Salazar

สุดยอดทางออก! ขอบคุณ! ด้วยเหตุผลบางอย่างการใช้งานtrigger('change')ไม่ได้สำหรับฉันดังนั้นฉันได้สร้าง CustomEvent ลงทะเบียนแล้วelement.dispatchEvent(myCustomEvent)
tbutcaru

8

คุณสามารถใช้ฟังก์ชั่นด้านล่างคุณยังสามารถเปลี่ยนองค์ประกอบประเภท

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

การเปลี่ยนแปลงมูลค่าขององค์ประกอบที่ซ่อนอยู่จะไม่ดำเนินการเหตุการณ์. change () โดยอัตโนมัติ ดังนั้นไม่ว่าคุณจะตั้งค่าที่ใดคุณก็ต้องบอกให้ jQuery เรียกใช้

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

ควรทำงานตามที่คาดไว้

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


1
ไม่ทำงานสำหรับฉัน ... อย่างไรก็ตามมันเป็นไปได้อย่างไรที่จะวางค่าลงในเขตข้อมูลที่ซ่อนอยู่ได้? : /
Simon Dugré

เฮ้ขอบคุณที่วางไม่ควรมี แต่การเปลี่ยนแปลงสามารถตรวจจับเหตุการณ์การเปลี่ยนแปลงเขตข้อมูลที่ซ่อนอยู่
Tarun Gupta

@KrisErickson ขอบคุณสำหรับซอฉันได้อัปเดตรหัสเพื่อให้สามารถตรวจจับการเปลี่ยนแปลงอย่างชัดเจนโปรดปฏิบัติตามซอที่อัปเดตjsfiddle.net/7CM6k/3
Tarun Gupta

1
@TarunGupta ใช่มันกำลังทำงานกับทริกเกอร์ แต่ไม่เปลี่ยนค่า เบราว์เซอร์จะไม่ดำเนินการเหตุการณ์การเปลี่ยนแปลงเมื่อสิ่งที่ซ่อนอยู่มีการเปลี่ยนแปลงมูลค่าคุณต้องดำเนินการด้วยตนเอง
Kris Erickson

ส่วนแรกของคำตอบนี้เกี่ยวกับการผูกกับเขตข้อมูลที่ซ่อนอยู่ทั้งหมดมีประโยชน์มาก ขอบคุณ!
ชาด


4

เป็นไปได้ที่จะใช้Object.defineProperty()เพื่อกำหนดคุณสมบัติ 'ค่า' ขององค์ประกอบอินพุตอีกครั้งและทำสิ่งใดระหว่างการเปลี่ยนแปลง

Object.defineProperty() ช่วยให้เราสามารถกำหนด getter และ setter สำหรับคุณสมบัติจึงควบคุมมันได้

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/


1
ฉันชอบวิธีการนี้โดยเฉพาะอย่างยิ่งเพราะคำตอบของทุกคนคือ "เรียกการเปลี่ยนแปลงด้วยตนเอง" ... ซึ่งไม่เป็นไปได้เสมอ
sMyles

1
นี่เกือบจะใช้ได้สำหรับฉันทุกอย่าง แต่ค่าสุดท้ายในเขตข้อมูลที่ซ่อนอยู่นั้นไม่ได้เปลี่ยนไปหากคุณตรวจสอบ jsfiddle ค่าของเขตข้อมูลที่ซ่อนอยู่จะไม่เปลี่ยนจาก '123' (โดยใช้ Chrome)
MetaGuru

ใกล้มาก แต่อย่างที่คนอื่น ๆ พูดถึงมันไม่ได้รักษาการอ้างอิงไปยัง mutator / setter ดั้งเดิมสำหรับฟิลด์ดังนั้นการอัปเดตจะไม่ส่งผลต่ออินพุตที่ซ่อนอยู่ ฉันกำลังโพสต์โซลูชันใหม่ที่รวมเอาส่วนของวิธีการนี้และโซลูชันจากstackoverflow.com/a/38802602/4342230
GuyPaddock

0

ตัวอย่างนี้ส่งคืนค่าฟิลด์แบบร่างทุกครั้งที่ฟิลด์แบบร่างที่ซ่อนอยู่เปลี่ยนค่าของมัน (เบราว์เซอร์ 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  });

       }
  };
})();

0

สร้างจากคำตอบของ Viktar ต่อไปนี้คือการใช้งานที่คุณสามารถโทรหาองค์ประกอบอินพุทที่ซ่อนอยู่ที่กำหนดหนึ่งครั้งเพื่อให้แน่ใจว่าเหตุการณ์การเปลี่ยนแปลงที่ตามมาจะเริ่มขึ้นเมื่อใดก็ตามที่มูลค่าขององค์ประกอบการเปลี่ยนแปลงมีดังนี้

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

เรียกเอกสารนี้ว่าพร้อมแล้วโดย:

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

-4

แม้ว่าหัวข้อนี้จะมีอายุ 3 ปี แต่นี่เป็นวิธีแก้ปัญหาของฉัน:

$(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");
    });
}

3
เหตุการณ์ความพร่ามัวจะถูกกระตุ้นเมื่ออินพุตสูญเสียการโฟกัส ไม่ใช่คำตอบที่ถูกต้องสำหรับอินพุตที่ซ่อนอยู่
manuerumx
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.