By Jimmy Ha


2012-11-07 19:57:50 8 Comments

I am trying to make a function go off when a particular div is created. In the simplest of terms, I have something like this:

<a href="" id="foo">Click me!</a>
<script>
$("#foo").live("click",function(e) {
    e.preventDefault();
    $(this).append($("<div />").html("new div").attr("id","bar"));
});
</script>

Before, I had mutation events listen for the creation of div#bar - something like this:

$("#bar").live("DOMNodeInserted", function(event) {
    console.log("a new div has been appended to the page");
});

Is there an equivalent using Mutation Observers? I tried attrchange.js featured on Can you have a javascript hook trigger after a DOM element's style object changes? but that plugin only detects when an element has been modified, not when it's created.

2 comments

@acdcjunior 2018-03-31 02:04:56

When using jQuery, the usage of MutationObservers can be simplified as shown below.

$("#btnAddDirectly").click(function () {
    $("#canvas").append($('<span class="stuff">new child direct</span>'));
});
$("#btnAddAsChildOfATree").click(function () {
    $("#canvas").append($('<div><div><span class="stuff">new child tree</span></div></div>'));
});

var obs = new MutationObserver(function(mutations, observer) {
  // using jQuery to optimize code
  $.each(mutations, function (i, mutation) {
    var addedNodes = $(mutation.addedNodes);
    var selector = "span.stuff"
    var filteredEls = addedNodes.find(selector).addBack(selector); // finds either added alone or as tree
    filteredEls.each(function () { // can use jQuery select to filter addedNodes
      alert('Insertion detected: ' + $(this).text());
    });
  });
});

var canvasElement = $("#canvas")[0];
obs.observe(canvasElement, {childList: true, subtree: true});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="canvas">
Canvas
</div>

<button id="btnAddDirectly">Add span directly to canvas</button>
<button id="btnAddAsChildOfATree">Add span as child of a tree</button>

It is always important to notice, the second argument to .observe(), MutationObserverInit, is important:

In the options, use childList: true if the span will only be added as a direct child. subTree: true if it can be at any level down below #canvas.

From the docs:

  • childList: Set to true if additions and removals of the target node's child elements (including text nodes) are to be observed.
  • subtree: Set to true if mutations to target and target's descendants are to be observed.

@apsillers 2012-11-07 21:17:13

This is code that listens for mutations on the childlist of #foo and checks to see if a child with the id of bar is added.

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

$("#foo").live("click",function(e) {
    e.preventDefault();
    $(this).append($("<div />").html("new div").attr("id","bar"));
});

// define a new observer
var obs = new MutationObserver(function(mutations, observer) {
    // look through all mutations that just occured
    for(var i=0; i<mutations.length; ++i) {
        // look through all added nodes of this mutation
        for(var j=0; j<mutations[i].addedNodes.length; ++j) {
            // was a child added with ID of 'bar'?
            if(mutations[i].addedNodes[j].id == "bar") {
                console.log("bar was added!");
            }
        }
    }
});

// have the observer observe foo for changes in children
obs.observe($("#foo").get(0), {
  childList: true
});

However, this only observes #foo. If you want to look for the addition of #bar as a new child of other nodes, you need to observe those potential parents with additional calls to obs.observe(). To observe a node with the id of baz, you might do:

obs.observe($('#baz').get(0), {
  childList: true,
  subtree: true
});

The addition of the subtree option means that the observer will look for the addition of #bar as either a child or a deeper descendant (e.g. grandchild).

@Šime Vidas 2012-11-07 21:20:39

A solution that only works in Chrome/Safari is hardly a legitimate solution.

@apsillers 2012-11-07 21:24:21

@ŠimeVidas Sorry, yes, my mistake; I had the vendor prefix in because I was testing in Chrome. I've now normalized the vendor prefixes and it otherwise should work fine as-is. It's MutationObserver in Firefox and WebKitMutationObserver in Webkit, but they work the same. Fiddle demo.

@apsillers 2012-11-07 21:32:08

@JimmyHa This will work in Firefox and Webkit browsers. Opera and IEdon't yet support Mutation Observers, so you'll need to use a fallback option like a DOM3 mutation event (or wait a long time for DOM4 methods to reach implementation maturity).

@Jimmy Ha 2012-11-07 22:37:16

@apsillers - Thanks! I modified your js to fit what I needed. Instead of looking for id, I was looking for a particular class: if ($(mutations[i].addedNodes[j]).hasClass("new_div_class")) { I'll just say in my ticket that if user wants the same feature-rich thing I'm trying to do in IE, they'll have to add scope to the project and pay me more. Are we sure mutation observers are better than mutation events? It seems like so many more lines of scripting to do the same thing.

@apsillers 2012-11-07 23:32:03

I believe the primary advantage of observers is the ability to narrow down exactly what kind of mutation event you want and what part of DOM you're interested in. With mutation events, the browser has to traverse potentially huge DOM trees every single time you make a change. With observers, you can narrow your sphere of interest by electing not to see subtrees, etc. See this post if you're interested in learning about the specific advantages.

@Omar 2013-11-30 10:29:02

Is it supported by window phone? Safari mobile, FF and chrome support it (new generation only).

Related Questions

Sponsored Content

55 Answered Questions

[SOLVED] How to create GUID / UUID?

  • 2008-09-19 20:01:00
  • Jason Cohen
  • 1941866 View
  • 4303 Score
  • 55 Answer
  • Tags:   javascript guid uuid

58 Answered Questions

[SOLVED] How do I check if an element is hidden in jQuery?

81 Answered Questions

[SOLVED] How do I detect a click outside an element?

32 Answered Questions

[SOLVED] jQuery scroll to element

33 Answered Questions

[SOLVED] Open a URL in a new tab (and not a new window)

  • 2011-02-05 15:52:13
  • Mark
  • 2704425 View
  • 2198 Score
  • 33 Answer
  • Tags:   javascript

39 Answered Questions

[SOLVED] Creating multiline strings in JavaScript

23 Answered Questions

[SOLVED] Event binding on dynamically created elements?

11 Answered Questions

[SOLVED] How can I add new array elements at the beginning of an array in Javascript?

  • 2011-11-10 00:35:22
  • Moon
  • 853638 View
  • 1655 Score
  • 11 Answer
  • Tags:   javascript arrays

15 Answered Questions

[SOLVED] How to move an element into another element?

  • 2009-08-14 20:14:45
  • Mark Richman
  • 1146057 View
  • 1725 Score
  • 15 Answer
  • Tags:   javascript jquery html

Sponsored Content