34

Lets say I have the following code that returns number of anchor elements on a page:

function getLinkCount() {
    alert("Links:" + $("a").length);
}

If I call in on document ready it would work as expected. But what if now a new link gets inserted into a page dynamically through Javascript, how can I get notified to run link counter function again? (I have no control over a script that could create a new link).

Basically I am looking for something similar to live() only that would be watching element creation event, something like:

$("a").live("create", getLinkCount);

that would trigger when a new element is created.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
serg
  • 109,619
  • 77
  • 317
  • 330

4 Answers4

43

You could use the DOMSubtreeModified event. For example:

$(document).bind('DOMSubtreeModified',function(){
  console.log("now there are " + $('a').length + " links on this page.");
})
mattsh
  • 5,713
  • 6
  • 23
  • 20
  • 2
    Good idea. Probably I can use even `DOMNodeInserted` event that has an actual element that was inserted as a target, so I can check whether or not it was an anchor before running a method. – serg Aug 02 '10 at 02:03
  • 2
    Right it doesn't work in IE , but it is the only way to be notified on DOM modifications by any means possible (non-jQuery). All other solutions I found assume the modifications are done via jQuery functions or, worse, make use of ugly setInterval(). In my specific case IE support is not required (yay!) – PowerKiKi Jun 21 '11 at 14:01
22

You can use the .livequery() plugin for this, it runs for each element, including new ones, like this:

$("a").livequery(getLinkCount);

However, this plugin is out-of-date and is not recommended for current versions of jQuery.

It's usually easier to do this when you create the elements though, for example if you're doing it after AJAX requests, the .ajaxComplete() handler may be a good place, for example:

$(document).ajaxComplete(getLinkCount);

This would run after each request, and since you normally create elements in your success handler, they would already be present when this complete handler runs.

Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
8

You can use the arrive.js library that I developed for the exact same purpose (it uses MutationObserver internally). Usage:

document.arrive('a', function(){
    // 'this' refers to the newly created element
    var newElem = this;
});
Uzair Farooq
  • 2,402
  • 3
  • 24
  • 37
  • 1
    This made my day! Happy that I stumble into this great plugin. – Aweda May 07 '20 at 12:19
  • Perfect, thank you so much Uzair! If you want to have new images do something once they're created and loaded, this is what you need. jQuery cannot do this. E.g. right at the top of your page: ```document.arrive("selector to your > img", function() { this.onload = function() { this.style.opacity = 1 } } )``` – chichilatte May 01 '23 at 22:43
6

The accepted answer is from 2010 and uses a jQuery plugin that is no longer being actively maintained. The highest upvoted answer suggests using DOMSubTreeModified which is now deprecated and should no longer be used.

Today, a MutationObserver is what you should use to detect when an element has been added to the DOM. MutationObservers are now widely supported across all modern browsers (Chrome 26+, Firefox 14+, IE11, Edge, Opera 15+, etc).

Here's a simple example of how you can use a MutationObserver to listen for when an element is added to the DOM.

For brevity, I'm using jQuery syntax to build the node and insert it into the DOM.

var myElement = $("<div>hello world</div>")[0];

var observer = new MutationObserver(function(mutations) {
   if (document.contains(myElement)) {
        console.log("It's in the DOM!");
        observer.disconnect();
    }
});

observer.observe(document, {attributes: false, childList: true, characterData: false, subtree:true});

$("body").append(myElement); // console.log: It's in the DOM!

The observer event handler will trigger whenever any node is added or removed from the document. Inside the handler, we then perform a contains check to determine if myElement is now in the document.

You don't need to iterate over each MutationRecord stored in mutations because you can perform the document.contains check directly upon myElement.

To improve performance, replace document with the specific element that will contain myElement in the DOM.

Elliot B.
  • 17,060
  • 10
  • 80
  • 101