jQuery – Evento Trigger quando um elemento é removido do DOM

Eu estou tentando descobrir como executar algum código js quando um elemento é removido da página:

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

existe um evento adaptado para isso, algo como:

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

obrigado.

Apenas verificado, já está embutido na versão atual do JQuery:

jQuery – v1.9.1

jQuery UI – v1.10.2

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

Importante : Essa é a funcionalidade do script da IU do Jquery (não da JQuery), portanto, é necessário carregar ambos os scripts (jquery e jquery-ui) para que funcione. Aqui está o exemplo: http://jsfiddle.net/72RTz/

Você pode usar events especiais do jQuery para isso.

Com toda a simplicidade,

Configuração:

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

Uso:

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

Adendo para responder aos comentários de Pierre e DesignerGuy:

Para não ter o callback triggersdo ao chamar $('.thing').off('destroyed') if (o.handler && o.type !== 'destroyed') { ... } $('.thing').off('destroyed') , mude a condição if para: if (o.handler && o.type !== 'destroyed') { ... }

Você pode ligar ao evento DOMNodeRemoved (parte da especificação WC3 do DOM Nível 3).

Funciona no IE9, versões mais recentes do Firefox e do Chrome.

Exemplo:

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

Você também pode receber uma notificação quando os elementos estão sendo inseridos por binding a DOMNodeInserted

Não há nenhum evento interno para remover elementos, mas você pode criar um usando o método de remoção padrão do jQuery falso. Observe que o retorno de chamada deve ser chamado antes de realmente removê-lo para manter a referência.

 (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: alguns problemas com esta resposta foram delineados por outros cartazes.

  1. Isso não funcionará quando o nó for removido via html() replace() ou outros methods jQuery
  2. Este evento borbulha
  3. jQuery UI substitui remover bem

A solução mais elegante para este problema parece ser: https://stackoverflow.com/a/10172676/216941

Hooking .remove() não é a melhor maneira de lidar com isso, pois há muitas maneiras de remover elementos da página (por exemplo, usando .html() , .replace() , etc).

Para evitar vários riscos de memory leaks, internamente o jQuery tentará chamar a function jQuery.cleanData() para cada elemento removido, independentemente do método usado para removê-lo.

Veja esta resposta para mais detalhes: vazamentos de memory javascript

Então, para melhores resultados, você deve ligar a function cleanData , que é exatamente o que o plugin jquery.event.destroyed faz:

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

Para quem usa o jQuery UI:

A jQuery UI substituiu alguns dos methods jQuery para implementar um evento remove que é manipulado não apenas quando você remove explicitamente o elemento especificado, mas também se o elemento é removido do DOM por qualquer método jQuery de limpeza automática (por exemplo, replace , html , etc). Isso basicamente permite que você coloque um gancho nos mesmos events que são triggersdos quando o jQuery está “limpando” os events e dados associados a um elemento DOM.

John Resig indicou que está aberto à ideia de implementar este evento em uma versão futura do núcleo do jQuery, mas não tenho certeza de onde ele está atualmente.

Eu não consegui obter essa resposta para trabalhar com o unbinding (apesar da atualização, veja aqui ), mas foi capaz de descobrir uma maneira de contornar isso. A resposta foi criar um evento especial ‘destroy_proxy’ que acionou um evento ‘destruído’. Você coloca o listener de evento em ‘destroyed_proxy’ e ‘destroyed’, então quando você quer desvincular, você apenas desassocia o evento ‘destroyed’:

 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++; }); 

Aqui está um violino

Solução sem usar a interface do usuário do jQuery

( Eu extraí essa extensão do framework da IU do jQuery )

Trabalha com: empty() e html() e 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 ); 

Com essa solução, você também pode desvincular o manipulador de events.

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

Tente! Exemplo

 $.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)

Eu gosto da resposta do mtkopone usando events especiais do jQuery, mas note que ele não funciona a) quando os elementos são desanexados em vez de removidos ou b) quando algumas bibliotecas antigas não-jquery usam innerHTML para destruir seus elementos

Não tenho certeza se há um identificador de evento para isso, então você teria que manter uma cópia do DOM e comparar com o DOM existente em algum tipo de loop de pesquisa – o que poderia ser bastante desagradável. O Firebug faz isso – se você inspecionar o HTML e executar algumas alterações no DOM, ele realçará as alterações em amarelo no console do Firebug por um curto período de tempo.

Alternativamente, você poderia criar uma function de remoção …

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

Isto é como criar um ouvinte de remoção ao vivo do jQuery:

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

Ou:

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

referenciando a @David answer:

Quando você quer fazer soo com outra function, por exemplo. html () como no meu caso, não esqueça de adicionar o retorno na nova function:

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

Este.

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

O evento “remove” do jQuery funciona bem, sem adição. Pode ser mais confiável na hora de usar um truque simples, em vez de remendar o jQuery.

Basta modificar ou adicionar um atributo no elemento que você está prestes a remover do DOM. Assim, você pode triggersr qualquer function de atualização, que apenas irá ignorar os elementos a serem destruídos, com o atributo “do_not_count_it”.

Suponha que tenhamos uma tabela com células correspondentes aos preços e que você precise mostrar apenas o último preço: Este é o seletor para acionar quando uma célula de preço é excluída (temos um botão em cada linha da tabela fazendo isso, não mostrado Aqui)

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

E aqui está uma function que encontra o último preço na tabela, não levando em conta o último, se foi o que foi removido. De fato, quando o evento “remove” é acionado e quando essa function é chamada, o elemento não é removido ainda.

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

No final, a function update_prices () funciona bem e depois disso, o elemento DOM é removido.