19

How can I detect when a new element has been added to the document in jquery ?

Explanation: I want to know when an element with class "column-header" has been added to the document. As I plan to run some javascript on those elements.

How can I do this ? I use jQuery javascript library.

Prakash Raman
  • 13,319
  • 27
  • 82
  • 132

11 Answers11

26

The accepted answer uses an obsolete plugin from 2011 and the highest upvoted answer uses Mutation events which are now deprecated.

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
22
$(document).bind('DOMNodeInserted', function(e) {
    console.log(e.target, ' was inserted');
});

DOMNodeInserted is a DOM level 3 Event. That in turn means, you need a fairly new browser to support that kind of event.

Reference: MDC

jAndy
  • 231,737
  • 57
  • 305
  • 359
  • Hmmm... This looks interesting. – Prakash Raman Jan 24 '11 at 16:04
  • 2
    This is the best choice for future development, IMO. It should be noted though, that this isn't supported in IE8 and lower. I've added an answer below if someone wants to just do a quick and dirty way to make something like this work in IE8 and lower and doesn't want to use livequery for some reason. – Ben Lesh Jul 17 '12 at 20:37
  • 2
    As of 2016 [mutation events](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events) are deprecated. It is advised not to use this kind of technique in old or new projects. Pitty. – nik_m Nov 03 '16 at 15:47
5

If you want to do some jQuery on it, you can also do something like livequery (extra plugin):

$('column-header').livequery(function()
{
    // do things here with your column-header, like binding new events and stuff.
    // this function is called when an object is added.
    // check the API for the deletion function and so on.
});

UPDATE: It seems that the link was broken. Try this link

Marnix
  • 6,384
  • 4
  • 43
  • 78
3

I would use setInterval to repeatedly check for element. eg.

var curLength=0;
setInterval(function(){
  if ($('.column-header').length!=curLength){
    curLength=$('.column-header').length;
    // do stuff here
  }
},100);

this code will check for any new .colum-header elements every 100 ms

Ivan
  • 3,567
  • 17
  • 25
  • 2
    It would be quite heavy, but without native support for NodeAdded event. this is as good as it gets. Both live query an mutation events most certainly use some sort of setInterval loop anyway. – Ivan Jan 24 '11 at 17:10
  • Wouldn't be heavy at all, set the Interval to a variable and clear it after. – NiCk Newman Aug 16 '15 at 14:56
2

I think the DOMNodeInserted method mentioned above is probably the sexiest choice, but if you need something that is going to work with IE8 and lower, you could do something like the following:

// wrap this up in en immediately executed function so we don't 
// junk up our global scope.
(function() {
   // We're going to use this to store what we already know about.
   var prevFound = null;

   setInterval(function() {
      // get all of the nodes you care about.
      var newFound = $('.yourSelector');

      // get all of the nodes that weren't here last check
      var diff = newFound.not(prevFound);

      // do something with the newly added nodes
      diff.addClass('.justGotHere');

      // set the tracking variable to what you've found.
      prevFound = newFound;
   }, 100);
})();

That is just the basic idea, you can change that however you want, make a method out of it, keep the return value of the setInterval so you can stop it, or whatever you need to do. But it should get the job done.

Ben Lesh
  • 107,825
  • 47
  • 247
  • 232
1

You should check out the jQuery Mutation Events. I believe that it is what you are looking for.

72lions
  • 680
  • 2
  • 7
  • 12
0

Up to 2013 MutationEvents are deprecated. If anyone else has got problems detecting new elements in the dom, you can use MutationObservers Instead: https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

dtdi
  • 60
  • 6
  • Don't just answer pasting a link, elaborate your answer. (I came here because your answer has flags) – BrunoLM Dec 24 '13 at 00:21
0

if you want to set same functions for all the elements with class column-header Then you may use jquery live()

$(".column-header").live("click",function(){});
Harish
  • 2,311
  • 4
  • 23
  • 28
0

How about using a poll - keep searching for an element with class "column-header", until you find it and then perform action. Seems simple.

bogatyrjov
  • 5,317
  • 9
  • 37
  • 61
  • Yep, that would work, but there would be a lag in the UI experience. Hoping to avoid that. – Prakash Raman Jan 24 '11 at 16:10
  • i think it depends on how deep and how wide your dom structure on the page is. I don't think that using some jquery plugins you will achieve much faster performance - should be tested on certain example. – bogatyrjov Jan 24 '11 at 21:07
-1
Just change this function call (observing).

Parameter 1 - Which element to monitor
Parameter 2 - Which element will trigger the function (parameter 3) when appears.
Parameter 3 - Function triggered


    observing('div#application', 'div.viewContainer', function(mutation){
        console.log('Mutation:', mutation)
    })

<html>
<head>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
/* Observing Easy */
function observing(who, forWhat, callBack){
    var observer = new MutationObserver(function(mutations) {
        
        mutations.forEach(mutation => {
            console.log(mutation.addedNodes[0])
            if ( mutation.addedNodes[0].matches(forWhat)){
                console.log('MATCH!');
                if(callBack!==undefined){
                    callBack(mutation)
                }
            }else{
                console.log('%cNOT match', 'color: #f00');
            }
        });

    });

    observer.observe($(who)[0], {attributes: false, childList: true, characterData: false, subtree:false});
}

$(document).ready(function(){

    
    /* Observing Usage */
    observing('div#application', 'div.viewContainer', function(mutation){
        console.log('Mutation:', mutation)
    })

    

    /* Adding Elements for Test */ 
    $("#application").append($("<div>Hello World</div>")[0]);
    $("#application").append($("<div class='contentFake'>ContentClassFAKE</div>")[0])
    $("#application").append($("<div class='contentFake'>ContentClass1</div>")[0])
    $("#application").append($("<div class='viewContainer'>ContentClass2</div>")[0])

    setTimeout(function(){
        $("#application").append($("<div class='contentFake'>ContentClass3</div>")[0])
    }, 1000)

    setTimeout(function(){
        $("#application").append($("<div class='viewContainer'>ContentClass4</div>")[0])
    }, 1000)
})
</script>
</head>
<body>
    <div id="application"></div>
</body>
</html>
  • While this code snippet may solve the problem, it doesn't explain why or how it answers the question. Please [include an explanation for your code](//meta.stackexchange.com/q/114762/269535), as that really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Luca Kiebel Jan 07 '22 at 19:50
-4

try this...

if($('.column-header')){  
//do something...
} 

or you can also do something like this..it will be more generic

jQuery.exists = function(selector) { return ($(selector).length > 0); }

if ($(selector).exists()) {
  // Do something
}
Vivek
  • 10,978
  • 14
  • 48
  • 66