web-dev-qa-db-fra.com

jQuery - Evénement déclencheur lorsqu'un élément est supprimé du DOM

J'essaie de comprendre comment exécuter du code JS lorsqu'un élément est supprimé de la page:

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

existe-t-il un événement sur mesure, quelque chose comme:

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

merci.

202
sa125

Vient de cocher, il est déjà intégré dans la version actuelle de JQuery:

jQuery - v1.9.1

interface utilisateur jQuery - v1.10.2

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

Important : il s'agit de la fonctionnalité du script Jquery UI (pas de JQuery), vous devez donc charger les deux scripts (jquery et jquery-ui) pour que cela fonctionne. Voici un exemple: http://jsfiddle.net/72RTz/

113
Philipp Munin

Vous pouvez utiliser événements spéciaux jQuery pour cela.

En toute simplicité,

Installer:

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

Usage:

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

Addendum pour répondre aux commentaires de Pierre et DesignerGuy:

Pour ne pas déclencher le rappel lors de l'appel de $('.thing').off('destroyed'), remplacez la condition if par: if (o.handler && o.type !== 'destroyed') { ... }.

194
mtkopone

Vous pouvez vous lier à l'événement DOMNodeRemoved (partie de la spécification DOM niveau 3 WC3).

Fonctionne dans IE9, les dernières versions de Firefox et Chrome.

Exemple:

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

Vous pouvez également recevoir une notification lorsque des éléments sont insérés en liant à DOMNodeInserted

48
Adam

Il n'y a pas d'événement intégré pour la suppression d'éléments, mais vous pouvez en créer un en utilisant la méthode de suppression par défaut de jQuery. Notez que le rappel doit être appelé avant de le supprimer pour conserver la référence.

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

Remarque: certains problèmes avec cette réponse ont été décrits par d'autres affiches.

  1. Cela ne fonctionnera pas lorsque le nœud sera supprimé via html()replace() ou d'autres méthodes jQuery.
  2. Cet événement bouillonne
  3. l'interface utilisateur jQuery annule également la suppression

La solution la plus élégante à ce problème semble être: https://stackoverflow.com/a/10172676/216941

37
David Hellsing

Le crochet .remove() n'est pas la meilleure solution, car il existe de nombreuses façons de supprimer des éléments de la page (par exemple, en utilisant .html() , .replace() , etc).

Afin d'éviter divers risques de fuite de mémoire, jQuery essayera d'appeler la fonction jQuery.cleanData() pour chaque élément supprimé, indépendamment du méthode utilisée pour l'enlever.

Voir cette réponse pour plus de détails: fuites de mémoire javascript

Donc, pour de meilleurs résultats, vous devriez associer la fonction cleanData, qui correspond exactement à ce que le plugin jquery.event.destroyed :

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

32
zah

Pour ceux qui utilisent l'interface utilisateur jQuery:

jQuery UI a remplacé certaines des méthodes jQuery pour implémenter un événement remove qui est géré non seulement lorsque vous supprimez explicitement l'élément donné, mais également si l'élément est supprimé du DOM par une méthode jQuery auto-nettoyante (par exemple, replace, html, etc.). En gros, cela vous permet d’accrocher les mêmes événements que ceux qui sont déclenchés lorsque jQuery "nettoie" les événements et les données associés à un élément DOM.

John Resig a indiqué qu'il était ouvert à l'idée d'implémenter cet événement dans une future version de jQuery Core, mais je ne suis pas sûr de son état actuel.

7
StriplingWarrior

Solution sans utiliser l'interface utilisateur de jQuery

(J'ai extrait cette extension du framework jQuery UI)

Fonctionne avec: empty() et html() et 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 );

Avec cette solution, vous pouvez également dissocier le gestionnaire d'événements.

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

Essayez-le! - Exemple

$.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();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>OnRemove event handler attached to elements `div`, `p` and `span`.</h3>
<div class="container">
  <br>
  <button onclick="RemoveDiv();">Click here to remove div below</button>
  <div id="DivToBeRemoved">
    DIV TO BE REMOVED 
    contains 1 p element 
    which in turn contains a span element
    <p>i am p (within div)
      <br><br><span>i am span (within div)</span></p>
  </div>
</div>

Supplémentaire Demo - jsBin

4
Legends

Je ne pouvais pas obtenir cette réponse travailler avec la suppression de la liaison (malgré la mise à jour voir ici ), mais j'ai pu trouver un moyen de la contourner. La réponse était de créer un événement spécial "destroy_proxy" qui déclenche un événement "détruit". Vous mettez l'écouteur d'événement à la fois sur "destroy_proxy" et sur "détruit", puis lorsque vous souhaitez dissocier, vous dissociez simplement l'événement "détruit":

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

Voici un violon

4
Bill Johnston

J'aime la réponse de mtkopone en utilisant des événements spéciaux jQuery, mais notez que cela ne fonctionne pas a) lorsque des éléments sont détachés au lieu d'être supprimés ou b) lorsque de vieilles bibliothèques autres que jQuery utilisent innerHTML pour détruire vos éléments.

3
Charon ME

Voici comment créer un jQuery écouteur de suppression en direct:

$(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)
  }
});
1
Buzogany Laszlo

L'événement "remove" de jQuery fonctionne correctement, sans ajout. Il serait peut-être plus fiable à temps d’utiliser une astuce simple au lieu de patcher jQuery.

Il suffit de modifier ou d'ajouter un attribut dans l'élément que vous êtes sur le point de supprimer du DOM. Ainsi, vous pouvez déclencher n'importe quelle fonction de mise à jour, qui ignorera simplement les éléments sur le point d'être détruits, avec l'attribut "do_not_count_it".

Supposons que nous ayons un tableau avec des cellules correspondant aux prix et que vous ne devez afficher que le dernier prix: il s'agit du sélecteur à déclencher lorsqu'une cellule de prix est supprimée (un bouton dans chaque ligne du tableau le fait, non affiché). ici)

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

Et voici une fonction qui trouve le dernier prix dans le tableau, sans tenir compte du dernier, si c'est celui qui a été supprimé. En effet, lorsque l'événement "remove" est déclenché, et lorsque cette fonction est appelée, l'élément n'est pas encore supprimé.

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

En fin de compte, la fonction update_prices () fonctionne correctement, puis l’élément DOM est supprimé.

1
philippe

Je ne suis pas sûr qu'il existe un descripteur d'événement pour cela. Vous devez donc conserver une copie du DOM et le comparer au DOM existant dans une sorte de boucle de scrutation - ce qui pourrait être assez désagréable. Firebug le fait cependant - si vous inspectez le code HTML et exécutez certaines modifications du DOM, les modifications apparaissent en jaune dans la console Firebug pendant une courte période.

Alternativement, vous pouvez créer une fonction de suppression ...

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

référençant à @ David réponse:

Lorsque vous voulez le faire avec une autre fonction, par exemple. html () comme dans mon cas, n'oubliez pas d'ajouter return dans la nouvelle fonction:

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

Cette.

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