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
ОБНОВЛЕНИЕ: событие изменения теперь запускается, когда значение скрытого поля обновляется.
Стивен

Ответы:

622

Так что это слишком поздно, но я нашел ответ на тот случай, если он пригодится всем, кто сталкивается с этой веткой.

Изменения значения для скрытых элементов не запускают автоматически событие .change (). Поэтому, где бы вы ни устанавливали это значение, вы также должны указать jQuery, чтобы оно вызывалось.

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

Раз это так,

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

должен работать как ожидалось.

yycroman
источник
5
Как .trigger()правило, лучше использовать просто вызов change()?
Ханна
1
Это работает, но кажется, что это вызывает событие изменения дважды! Это как если бы я поставил этот код, он дважды сработал, если я удалю код, триггеры не будут с е. !!
Янкс из Венесуэлы
1
Чтобы заставить его работать так же, как changeсобытие, вы должны добавить код, setUserID()чтобы проверить, действительно ли значение изменяется. if ($('#userid').val() != myVaule) { // set val() and trigger change }
nnattawat
1
Это особенно полезно, если вы пытаетесь перехватить событие «change», которое изменяется с помощью javascript, иначе изменения, сделанные javascript, не могут быть перехвачены .change (обработчик) или .on («change», обработчик)
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] );
lulalala
источник
AFAIK mutationobserver также НЕ запускается при изменении внутри текстового поля (независимо от того, скрыто оно или нет)
Ole Albers
3
Прекрасно работает! @OleAlbers - OP спросил оinput[type=hidden]
Шей
1
Я использовал это в сочетании с функцией, которая использовала команду map jquery для получения коллекции значений скрытого поля ввода. Большое спасибо @lulalala!
AdamJones
2
Просто и легко понять. Это решение, в отличие от решений «вы должны инициировать событие при изменении значения», не полагается на то, что программист имеет доступ к коду в точке изменения значения, что делает его более полезным, пока вы не не должен поддерживать версию старше, чем IE11. Это отлично сработало для меня. Спасибо
Джо Салазар
Отличное решение! Спасибо! По какой-то причине у 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
Не работает для меня ... В любом случае, как можно было вставить значение в скрытое поле? : /
Саймон Дугре
Эй, спасибо, там не должно быть вставки, но изменение может обнаружить скрытое событие смены поля
Тарун Гупта
@KrisErickson Спасибо за скрипку, я обновил код, чтобы он мог явно обнаруживать изменения. Пожалуйста, следуйте обновленной скрипте jsfiddle.net/7CM6k/3
Тарун Гупта
1
@TarunGupta да, он работает на триггере, но не меняет значение. Браузеры не запускают событие изменения, когда скрытое имеет измененное значение, вы должны сделать это вручную.
Крис Эриксон
Первая часть этого ответа о привязке ко всем скрытым полям была очень полезной. Спасибо!
Чад
6
$('#userid').change(function(){
  //fire your ajax call  
});

$('#userid').val(10).change();
Дигамбар Патил
источник
4

Это можно использовать Object.defineProperty()для того, чтобы переопределить свойство 'value' элемента input и сделать что-нибудь во время его изменения.

Object.defineProperty() позволяет нам определять геттер и сеттер для свойства, таким образом управляя им.

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
Очень близко, но, как уже упоминали другие, он не поддерживает ссылку на исходный мутатор / установщик для поля, поэтому обновления не влияют на сам скрытый ввод. Я публикую новое решение, которое включает в себя части этого подхода и решение от 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  });

       }
  };
})();
user2677034
источник
0

Основываясь на ответе Виктора , вот реализация, которую вы можете вызвать один раз для данного скрытого элемента ввода, чтобы гарантировать, что последующее событие изменения будет запущено при изменении значения элемента ввода:

/**
 * 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]);
});
GuyPaddock
источник
-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");
    });
}
mdbxz
источник
3
событие размытия запускается только тогда, когда вход теряет фокус.
Неправильный