jQuery - Detecta alteração de valor no campo de entrada oculto

270

Eu tenho um campo de texto oculto cujo valor é atualizado por meio de uma resposta AJAX.

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

Quando esse valor muda, eu gostaria de disparar uma solicitação AJAX. Alguém pode aconselhar sobre como detectar a alteração?

Eu tenho o seguinte código, mas não sei como procurar o valor:

$('#userid').change( function() {  
    alert('Change!'); 
}) 
Ben
fonte
2
Se for atualizado por meio de uma resposta ajax, por que você não aciona a nova solicitação ajax na função de sucesso da resposta?
BonyT
2
$ ( '# ID do usuário') val () irá dar-lhe o valor, se é isso que você está pedindo.
BonyT
UPDATE: um evento de alteração agora é acionado quando o valor de um campo oculto é atualizado.
430 Steven

Respostas:

622

Portanto, é tarde demais, mas eu descobri uma resposta, caso ela se torne útil para qualquer pessoa que se depare com esse tópico.

Alterações no valor de elementos ocultos não acionam automaticamente o evento .change (). Portanto, onde quer que você esteja definindo esse valor, você também precisa dizer ao jQuery para ativá-lo.

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

Quando esse for o caso,

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

deve funcionar como esperado.

yycroman
fonte
5
.trigger()Geralmente é melhor usar do que apenas ligar change()?
21713 Hanna
1
Funciona, mas parece que aciona o evento de alteração duas vezes !. É como se eu colocasse esse código, ele dispara duas vezes, se eu remover o código, não dispara p / e. !!
Janx da Venezuela 13/08
1
Para que ele se comporte da mesma forma que o changeevento, você deve adicionar o código setUserID()para verificar se o valor é realmente alterado ou não. if ($('#userid').val() != myVaule) { // set val() and trigger change }
Nttawat 19/11/2015
1
Isso é especialmente útil se você estiver tentando capturar um evento "change" que, como sendo alterado via javascript, caso contrário, as alterações feitas pelo javascript não poderão ser capturadas pelo .change (manipulador) ou .on ("change", manipulador)
JJK
7
então, se eu não tiver controle sobre a função que altera o valor do campo oculto (ou seja, não é possível disparar o gatilho), essa solução não funcionará, certo?
osama yaccoub
31

Como a entrada oculta não aciona o evento "change" na alteração, usei o MutationObserver para acionar isso.

(Às vezes, as alterações ocultas do valor de entrada são feitas por outros scripts que você não pode modificar)

Isso não funciona no IE10 e abaixo

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
fonte
AFAIK o mutationobserver também não fica dispararam sobre uma mudança dentro de um campo de texto (não importa se oculta ou não)
Ole Albers
3
Funciona bem! @OleAlbers - OP perguntado sobreinput[type=hidden]
Shay
1
Eu usei isso em combinação com uma função que estava usando o comando map do jquery para recuperar uma coleção de valores de campos de entrada ocultos. Muito obrigado @lulalala!
AdamJones 2/17/17
2
Simples e fácil de se entender. Essa solução, ao contrário das soluções "você deve acionar o evento ao alterar o valor", não depende do programador ter acesso ao código no ponto em que o valor é alterado, tornando-o mais útil desde que você não precisa suportar uma versão anterior ao IE11. Funcionou muito bem para mim. Obrigado
Joe Salazar
Ótima solução! Obrigado! Por alguma razão o trigger('change')não funcionou para mim, então eu criei um CustomEvent, registrou e depoiselement.dispatchEvent(myCustomEvent)
tbutcaru
8

Você pode simplesmente usar a função abaixo. Você também pode alterar o elemento de texto.

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

Alterações no valor de elementos ocultos não acionam automaticamente o evento .change (). Portanto, onde quer que você esteja definindo esse valor, você também precisa dizer ao jQuery para ativá-lo.

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

deve funcionar como esperado.

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

Tarun Gupta
fonte
1
Não está funcionando para mim ... De qualquer forma, como seria possível colar valor em um campo oculto? : /
Simon Dugré 18/07
Hey Thanks, colar não deveria estar lá, mas a mudança pode detectar o evento de alteração de campo escondida
Tarun Gupta
@KrisErickson Obrigado pelo violino, eu tenho atualizado o código para que ele possa detectar a mudança de forma explícita, siga as atualizadas fiddle jsfiddle.net/7CM6k/3
Tarun Gupta
1
@TarunGupta sim, está trabalhando no gatilho, mas não alterando o valor. Os navegadores não acionam o evento de alteração quando um valor oculto é alterado, você deve fazer isso manualmente.
Kris Erickson
A primeira parte desta resposta sobre a ligação a todos os campos ocultos foi muito útil. Obrigado!
Chad
6
$('#userid').change(function(){
  //fire your ajax call  
});

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

É possível usar Object.defineProperty()para redefinir a propriedade 'value' do elemento de entrada e fazer qualquer coisa durante sua alteração.

Object.defineProperty() permite definir um getter e setter para uma propriedade, controlando-a.

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
fonte
1
Eu gosto dessa abordagem, especialmente porque a resposta de todos os outros é "você mesmo desencadeie a mudança" ... o que nem sempre é viável.
S17:
1
isso está quase funcionando para mim, tudo, menos o valor final no campo oculto, na verdade, não está sendo alterado. Se você verificar o jsfiddle, o valor do campo oculto não muda de '123' (usando o Chrome)
MetaGuru
Muito próximo, mas como os outros mencionaram, ele não mantém uma referência ao mutador / setter original para o campo, portanto, as atualizações falham em afetar a própria entrada oculta. Estou postando uma nova solução que incorpora peças desta abordagem e a de stackoverflow.com/a/38802602/4342230
GuyPaddock
0

Este exemplo retorna o valor do campo de rascunho sempre que o campo de rascunho oculto altera seu valor (navegador 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
fonte
0

Partindo da resposta da Viktar , aqui está uma implementação que você pode chamar uma vez em um determinado elemento de entrada oculto para garantir que o evento de alteração subsequente seja acionado sempre que o valor do elemento de entrada for alterado:

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

Chame isso no documento pronto da seguinte maneira:

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

Embora este segmento tenha 3 anos, aqui está minha solução:

$(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
fonte
3
o evento de desfoque é acionado apenas quando a entrada perde o foco. Não é uma resposta válida para uma entrada escondida
manuerumx