Detecta cambios de contenido de elementos con jQuery

113

change() La función funciona y detecta cambios en los elementos del formulario, pero ¿hay alguna forma de detectar cuándo se cambió el contenido de un elemento DOM?

Esto no funciona, a menos que #contentsea ​​un elemento de formulario.

$("#content").change( function(){
    // do something
});

Quiero que esto se active al hacer algo como:

$("#content").html('something');

Además, la función html()o append()no tiene devolución de llamada.

¿Alguna sugerencia?

Elzo Valugi
fuente
vieja pregunta, lo sé, pero verifique mi respuesta para una solución elegante stackoverflow.com/a/23826615/744975
Andrew Atkinson

Respuestas:

26

Estos son eventos de mutación .

No he usado API de eventos de mutación en jQuery, pero una búsqueda superficial me llevó a este proyecto en GitHub. Desconozco la madurez del proyecto.

jrharshath
fuente
17
Este complemento de eventos de mutación no funcionará, porque simplemente conecta los eventos a los métodos de mutación de jQuery. Se activan cuando jQuery intenta cambiar los elementos, pero no cuando los elementos se cambian desde fuera de jQuery. No ven cambios en el documento. En su lugar
consulte
10
Buscar en Google y publicar un enlace a una biblioteca que nunca ha probado no es muy útil. (Comentando porque se me pidió que lo hiciera al votar en contra.)
Deja de difamar a Monica Cellio
27
Los eventos de mutación están en desuso ; no los use.
Brock Adams
La alternativa a los eventos de mutación parecen ser MutationObservers .
WoodrowShigeru
69

Sé que esta publicación tiene un año, pero me gustaría brindar un enfoque de solución diferente para aquellos que tienen un problema similar:

  1. El evento de cambio de jQuery se usa solo en los campos de entrada del usuario porque si se manipula algo más (por ejemplo, un div), esa manipulación proviene del código. Entonces, encuentre dónde ocurre la manipulación y luego agregue lo que necesite allí.

  2. Pero si eso no es posible por alguna razón (está utilizando un complemento complicado o no puede encontrar ninguna posibilidad de "devolución de llamada"), entonces el enfoque de jQuery que sugeriría es:

    a. Para una manipulación DOM simple, use jQuery encadenando y atravesando,$("#content").html('something').end().find(whatever)....

    si. Si desea hacer otra cosa, emplee jQuery bindcon evento personalizado ytriggerHandler

    $("#content").html('something').triggerHandler('customAction');
    
    $('#content').unbind().bind('customAction', function(event, data) {
       //Custom-action
    });

Aquí hay un enlace al controlador de activación de jQuery: http://api.jquery.com/triggerHandler/

Kyle
fuente
1
Pensamiento final. aunque eso debería ser bastante completo arriba: podría actualizar el valor de un campo de entrada oculto con el del #content html y luego vincular el evento de cambio al campo de entrada oculto :) muchas opciones
Kyle
7
+1 "Encuentra dónde ocurre la manipulación y luego agrega lo que necesites allí". Se solucionó mi problema en 2 segundos sin ningún truco / complemento :)
Hartley Brody
El único cambio que sugiero aquí es que bindestá esperando que su controlador devuelva un bool.
Serj Sagan
15

El navegador no activará el evento onchange para <div>elementos.

Creo que el razonamiento detrás de esto es que estos elementos no cambiarán a menos que sean modificados por JavaScript. Si ya tiene que modificar el elemento usted mismo (en lugar de que lo haga el usuario), puede simplemente llamar al código correspondiente correspondiente al mismo tiempo que modifica el elemento, así:

 $("#content").html('something').each(function() { });

También puede disparar manualmente un evento como este:

 $("#content").html('something').change();

Si ninguna de estas soluciones funciona para su situación, ¿podría brindar más información sobre lo que está tratando de lograr específicamente?

TM.
fuente
11
Esto supone que ha escrito todo el javascript, lo que puede no ser el caso.
Myster
¡¡¡¡GRACIAS!!!! Esto solo me ayudó a resolver un problema que había estado mirando durante 6 horas.
Jordan Parmer
Exactamente lo que necesitaba.
smac89
15

¿qué pasa con http://jsbin.com/esepal/2

$(document).bind("DOMSubtreeModified",function(){
  console.log($('body').width() + ' x '+$('body').height());
})

Este evento ha quedado obsoleto en favor de la API de Mutation Observer

FDisk
fuente
1
no es mala idea, aunque me pregunto cuánto apoyo tiene. developer.mozilla.org/en/DOM/DOM_event_reference/…
Elzo Valugi
¿Cómo supervisa un elemento específico para detectar cambios? Actualmente, el documento supervisa toda la página.
Patoshi パ ト シ
3

No es estrictamente una respuesta de jQuery, pero es útil mencionarlo para la depuración.

En Firebug, puede hacer clic derecho en un elemento en el árbol DOM y configurar 'Romper en cambio de atributo':

Elemento clic derecho en Firebug con Break on Attribute Change resaltado

Cuando se cambia un atributo en una secuencia de comandos, aparecerá la ventana de depuración y podrá rastrear lo que está sucediendo. También hay una opción para la inserción de elementos y la eliminación de elementos a continuación (inútilmente oscurecida por la ventana emergente en la captura de pantalla).

John Reid
fuente
1
Esto es útil, pero no es exactamente lo que estaba pidiendo. Esto detectará cosas como cuando cambia una clase o cuando se agrega o cambia un atributo de estilo. No comprobará cuándo cambia el contenido en el interior del nodo. Por ejemplo, si algún javascript en algún lugar cambia un nodo de <span> hola </span> a <span> Mundo </span>, esto no lo detectará
Joshua Soileau
2

Estoy desarrollando una pequeña biblioteca JS llamada mutabor ( https://github.com/eskat0n/mutabor ) que pretendía simplificar el uso de eventos de mutación DOM. Consulte demo.html para ver ejemplos.

Eskat0n
fuente
1

A menudo, una forma simple y eficaz de lograr esto es realizar un seguimiento de cuándo y dónde está modificando el DOM.

Puede hacer esto creando una función central que siempre sea responsable de modificar el DOM. Luego, realice la limpieza que necesite en el elemento modificado desde dentro de esta función.

En una aplicación reciente, no necesitaba una acción inmediata, así que usé una devolución de llamada para la función handly load (), para agregar una clase a cualquier elemento modificado y luego actualicé todos los elementos modificados cada pocos segundos con un temporizador setInterval.

$($location).load("my URL", "", $location.addClass("dommodified"));

Entonces puedes manejarlo como quieras, p. Ej.

setInterval("handlemodifiedstuff();", 3000); 
function handlemodifiedstuff()
{
    $(".dommodified").each(function(){/* Do stuff with $(this) */});
}
Antony Carthy
fuente
3
Esto supone que ha escrito todo el javascript, lo que puede no ser el caso.
Myster
1

Puede agregar una opción de devolución de llamada a la función html (o cualquier otra):

$.fn.oldHtml = $.fn.html;
$.fn.html = function(html,fn){
  fn = fn || function(){};
  var result =  this.oldHtml(html);
  fn();
  return result;
};
$('body').html(11,function(){alert("haha");});

Demo aquí.

Realiza el cambio en algún elemento, no el elemento se ve obligado a cambiar por algo que tiene que atrapar.


fuente
Tuve que resolver este problema hoy. No pude editar el código que realmente llamaba html () porque está en una biblioteca de terceros. Una versión modificada de esto fue perfecta para mí. Hice esto: $ .fn.oldHtml = $ .fn.html (); $ .fn.html = function (e) {var result = this.oldHtml (e); this.trigger ('afterHtmlChange', e);} Ahora puedo vincular cualquier evento que desee al evento afterHtmlChange recién creado en cualquier elemento, que se activará siempre que algo llame al html () fn de jQuery.
Daniel Howard
Vaya, pequeño error. Fn en mi comentario anterior debería ser: function (e) {var result = this.oldHtml (e); this.trigger ('afterHtmlChange', e); return result;}
Daniel Howard
0

Escribí un fragmento que verificará el cambio de un elemento en un evento.

Entonces, si está utilizando un código javascript de terceros o algo así y necesita saber cuándo aparece algo o cambia cuando ha hecho clic, entonces puede hacerlo.

Para el siguiente fragmento, digamos que necesita saber cuándo cambia el contenido de una tabla después de hacer clic en un botón.

$('.button').live('click', function() {

            var tableHtml = $('#table > tbody').html();
            var timeout = window.setInterval(function(){

                if (tableHtml != $('#table > tbody').
                    console.log('no change');
                } else {
                    console.log('table changed!');
                    clearInterval(timeout);
                }

            }, 10);
        });

Pseudo código:

  • Una vez que haces clic en un botón
  • se captura el html del elemento que espera cambiar
  • luego revisamos continuamente el html del elemento
  • cuando encontramos que el html es diferente, dejamos de verificar
Andrew Atkinson
fuente
0

Podemos lograr esto usando Mutation Events . Según www.w3.org, el módulo de eventos de mutación está diseñado para permitir la notificación de cualquier cambio en la estructura de un documento, incluidas las modificaciones de atributo y texto. Para más detalles EVENTOS DE MUTACIÓN

Por ejemplo :

$("body").on('DOMSubtreeModified', "#content", function() {
    alert('Content Modified'); // do something
});
Sanchit Gupta
fuente
Esto ha quedado obsoleto por un tiempo. Uno debería usar Mutation Observers (mismo concepto)
Carles Alcolea
-3

No es posible, creo, es decir, tiene un evento de cambio de contenido, pero ciertamente no es x-browser

¡Debo decir que no es posible sin un desagradable intervalo resoplando de fondo!

cuadrado rojo
fuente
21
¡nada es imposible!
jrharshath