jQuery: evento desencadenante cuando se elimina un elemento del DOM

Estoy intentando descubrir cómo ejecutar código js cuando un elemento se elimina de la página:

jQuery('#some-element').remove(); // remove some element from the page /* need to figure out how to independently detect the above happened */ 

¿Hay algún evento adaptado para eso, algo así como:

 jQuery('#some-element').onremoval( function() { // do post-mortem stuff here }); 

Gracias.

Acabo de verificar, ya está incorporado en la versión actual de JQuery:

jQuery – v1.9.1

jQuery UI – v1.10.2

 $("#myDiv").on("remove", function () { alert("Element was removed"); }) 

Importante : Esta es la funcionalidad del script de Jquery UI (no JQuery), por lo que debe cargar ambos scripts (jquery y jquery-ui) para que funcione. Aquí está el ejemplo: http://jsfiddle.net/72RTz/

Puede usar eventos especiales jQuery para esto.

En toda simplicidad,

Preparar:

 (function($){ $.event.special.destroyed = { remove: function(o) { if (o.handler) { o.handler() } } } })(jQuery) 

Uso:

 $('.thing').bind('destroyed', function() { // do stuff }) 

Adición para responder a los comentarios de Pierre y DesignerGuy:

Para no tener el disparo de callback cuando se llama a $('.thing').off('destroyed') , cambie la condición if a: if (o.handler && o.type !== 'destroyed') { ... }

Puede vincularse al evento DOMNodeRemoved (parte de la especificación WC3 de DOM Level 3).

Funciona en IE9, las últimas versiones de Firefox y Chrome.

Ejemplo:

 $(document).bind("DOMNodeRemoved", function(e) { alert("Removed: " + e.target.nodeName); }); 

También puede recibir una notificación cuando los elementos se insertan al enlazar con DOMNodeInserted

No existe un evento incorporado para eliminar elementos, pero puede crear uno mediante el método de eliminación predeterminado de jQuery que extiende la falsa. Tenga en cuenta que se debe llamar a la callback antes de eliminarla para mantener la referencia.

 (function() { var ev = new $.Event('remove'), orig = $.fn.remove; $.fn.remove = function() { $(this).trigger(ev); return orig.apply(this, arguments); } })(); $('#some-element').bind('remove', function() { console.log('removed!'); // do pre-mortem stuff here // 'this' is still a reference to the element, before removing it }); // some other js code here [...] $('#some-element').remove(); 

Nota: algunos otros problemas han descrito algunos problemas con esta respuesta.

  1. Esto no funcionará cuando el nodo se elimine a través de html() replace() u otros métodos de jQuery
  2. Este evento estalla
  3. Las anulaciones de JQuery UI eliminan también

La solución más elegante a este problema parece ser: https://stackoverflow.com/a/10172676/216941

.remove() no es la mejor manera de manejar esto, ya que hay muchas maneras de eliminar elementos de la página (por ejemplo, usando .html() , .replace() , etc.).

Para evitar varios riesgos de pérdida de memoria, internamente, jQuery intentará llamar a la función jQuery.cleanData() para cada elemento eliminado, independientemente del método utilizado para eliminarlo.

Vea esta respuesta para más detalles: pérdidas de memoria de JavaScript

Por lo tanto, para obtener mejores resultados, debe conectar la función cleanData , que es exactamente lo que hace el complemento jquery.event.destroyed :

http://v3.javascriptmvc.com/jquery/dist/jquery.event.destroyed.js

Para aquellos que usan jQuery UI:

jQuery UI ha anulado algunos de los métodos jQuery para implementar un evento remove que se maneja no solo cuando se elimina explícitamente el elemento dado, sino también si el elemento se elimina del DOM mediante cualquier método jQuery autolimpiante (por ejemplo, replace , html , etc.). Esto básicamente le permite poner un gancho en los mismos eventos que se activan cuando jQuery está “limpiando” los eventos y los datos asociados con un elemento DOM.

John Resig ha indicado que está abierto a la idea de implementar este evento en una versión futura de jQuery core, pero no estoy seguro de dónde se encuentra actualmente.

No pude obtener esta respuesta para trabajar con la desvinculación (a pesar de que la actualización se ve aquí ), pero pude encontrar una forma de evitarla. La respuesta fue crear un evento especial ‘destroy_proxy’ que desencadenó un evento ‘destruido’. Pones al oyente del evento tanto en ‘destroyed_proxy’ como ‘destruido’, luego cuando deseas desvincularlo, simplemente desvinculas el evento ‘destruido’:

 var count = 1; (function ($) { $.event.special.destroyed_proxy = { remove: function (o) { $(this).trigger('destroyed'); } } })(jQuery) $('.remove').on('click', function () { $(this).parent().remove(); }); $('li').on('destroyed_proxy destroyed', function () { console.log('Element removed'); if (count > 2) { $('li').off('destroyed'); console.log('unbinded'); } count++; }); 

Aquí hay un violín

Solución sin usar la interfaz de usuario jQuery

( He extraído esta extensión del marco de jQuery UI )

Funciona con: empty() y html() y remove()

 $.cleanData = ( function( orig ) { return function( elems ) { var events, elem, i; for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { try { // Only trigger remove when necessary to save time events = $._data( elem, "events" ); if ( events && events.remove ) { $( elem ).triggerHandler( "remove" ); } // Http://bugs.jquery.com/ticket/8235 } catch ( e ) {} } orig( elems ); }; } )( $.cleanData ); 

Con esta solución también puede desvincular el controlador de eventos.

 $("YourElemSelector").off("remove"); 

¡Intentalo! – Ejemplo

 $.cleanData = (function(orig) { return function(elems) { var events, elem, i; for (i = 0; (elem = elems[i]) != null; i++) { try { // Only trigger remove when necessary to save time events = $._data(elem, "events"); if (events && events.remove) { $(elem).triggerHandler("remove"); } // Http://bugs.jquery.com/ticket/8235 } catch (e) {} } orig(elems); }; })($.cleanData); $("#DivToBeRemoved").on("remove", function() { console.log("div was removed event fired"); }); $("p").on("remove", function() { console.log("p was removed event fired"); }); $("span").on("remove", function() { console.log("span was removed event fired"); }); // $("span").off("remove"); $("#DivToBeRemoved").on("click", function() { console.log("Div was clicked"); }); function RemoveDiv() { // $("#DivToBeRemoved").parent().html(""); $("#DivToBeRemoved").remove(); } 
  

OnRemove event handler attached to elements `div`, `p` and `span`.


DIV TO BE REMOVED contains 1 p element which in turn contains a span element

i am p (within div)

i am span (within div)

Me gusta la respuesta de mtkopone usando eventos especiales jQuery, pero tenga en cuenta que no funciona a) cuando los elementos se separan en lugar de eliminarse ob) cuando algunas bibliotecas antiguas que no son jquery usan innerHTML para destruir sus elementos

No estoy seguro de que haya un identificador de evento para esto, por lo que tendrías que conservar una copia del DOM y compararlo con el DOM existente en algún tipo de ciclo de votación, lo que podría ser bastante desagradable. Firebug hace esto: si inspecciona el HTML y ejecuta algunos cambios DOM, resalta los cambios en amarillo en la consola Firebug por un corto tiempo.

Alternativamente, podría crear una función de eliminación …

 var removeElements = function(selector) { var elems = jQuery(selector); // Your code to notify the removal of the element here... alert(elems.length + " elements removed"); jQuery(selector).remove(); }; // Sample usage removeElements("#some-element"); removeElements("p"); removeElements(".myclass"); 

Esta es la forma de crear un oyente de eliminación de jQuery Live :

 $(document).on('DOMNodeRemoved', function(e) { var $element = $(e.target).find('.element'); if ($element.length) { // do anything with $element } }); 

O:

 $(document).on('DOMNodeRemoved', function(e) { $(e.target).find('.element').each(function() { // do anything with $(this) } }); 

haciendo referencia a la respuesta de @David:

Cuando quiera hacer soo con otra función, ej. html () como en mi caso, no olvides agregar return en una nueva función:

 (function() { var ev = new $.Event('html'), orig = $.fn.html; $.fn.html = function() { $(this).trigger(ev); return orig.apply(this, arguments); } })(); 

Esta.

 $.each( $('#some-element'), function(i, item){ item.addEventListener('DOMNodeRemovedFromDocument', function(e){ console.log('I has been removed'); console.log(e); }) }) 

El evento “eliminar” de jQuery funciona bien, sin adición. Puede ser más confiable a tiempo para usar un truco simple, en lugar de parchear jQuery.

Simplemente modifique o agregue un atributo en el elemento que está a punto de eliminar del DOM. Por lo tanto, puede activar cualquier función de actualización, que simplemente ignorará los elementos en el camino para ser destruidos, con el atributo “do_not_count_it”.

Supongamos que tenemos una tabla con celdas que corresponde a los precios, y que solo debe mostrar el último precio: este es el selector que se activa cuando se elimina una celda de precio (tenemos un botón en cada línea de la tabla haciendo eso, no se muestra aquí)

 $('td[validity="count_it"]').on("remove", function () { $(this).attr("validity","do_not_count_it"); update_prices(); }); 

Y aquí hay una función que encuentra el último precio en la tabla, sin tener en cuenta el último, si fue el que se eliminó. De hecho, cuando se desencadena el evento “quitar”, y cuando se llama a esta función, el elemento no se elimina aún.

 function update_prices(){ var mytable=$("#pricestable"); var lastpricecell = mytable.find('td[validity="count_it"]').last(); } 

Al final, la función update_prices () funciona bien, y después de eso, el elemento DOM se elimina.