2

I am currently learning Javascript and one of my chapters is "Mutation Observer". I am trying to create a simple function which detects if a new div was added to the page and display it in the console. However, I am getting this message and I struggle to find a solution how to fix this error. I will be very grateful if someone can explain to me what I am doing wrong. Thank you in advance!

Uncaught TypeError: Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.

So far this is the code I wrote:

document.getElementById("Button").onclick = function(){
  var Add = document.createElement('div');
    Add.setAttribute("class", "Alpha");
    Add.appendChild(document.createTextNode("Test"));
    document.getElementById('Frame').appendChild(Add);
};

var Divs = document.querySelectorAll("div");
var Observer = new MutationObserver(function(mutations){
  mutations.forEach(function(mutation){
    for(var i = 0; i <= mutation.addedNodes.length; i++){
      if(!(mutation.addedNodes[i] == null)){
        console.log(mutation.addedNodes[i].innerHTML);
      }
    }
  });
});
Observer.observe(Divs, {childList: true, subtree:true});
.Alpha{
  color:red;
}
<button id="Button">Generate a new div</button>
<div id="Frame"></div>
George Smith
  • 415
  • 8
  • 25

1 Answers1

3

The issue is explained in the error message. The observe function expects a Node but you're assigning the return value of querySelectorAll lookup which actually returns a NodeList (so one or many Nodes). Even if it finds nothing, it'll return an empty NodeList and still be invalid.

In your instance, you appear to be pushing items into a DIV with an id of Frame so we'll attach our MutationObserver onto that and watch for any changes to its children. Finally, we'll push any changed nodes into an array and console log the contents so you can see what it's capturing,

var target = document.getElementById('Frame');
var insertedNodes = [];
var Observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        for(var i = 0; i < mutation.addedNodes.length; i++) {
            insertedNodes.push(mutation.addedNodes[i]);
        }
    });
});

Observer.observe(target, {
    childList: true,
    subtree:true
});

console.log(insertedNodes);
Dwayne Charrington
  • 6,524
  • 7
  • 41
  • 63
  • Thank you very much for the fast response. It works great. However, I have a few following questions. 1) What if I want to observe if a random div element is added to the DOM? I assume that you have to change `var target=document.getElementById('Frame')` to `var target=document.body` but then you will not only be observing div elements but span, p, a, etc. too. 2) Is there a way to crumble a div which has child elements inside? I I tried to make a second `for` loop but this time with `insertedNodes.childNodes.length;` but it doesn't return any result. [JsFiddle](https://jsfiddle.net/vaygja8L/) – George Smith Jul 06 '17 at 11:53
  • Your jsfiddle enumerates only direct children of each inserted node. You might want to use .getElementsByTagName('div') instead. But beware of the text nodes as they don't have any child nodes so check first: `if (node.children && node.children.length)` for example. – wOxxOm Jul 06 '17 at 13:37
  • @wOxxOm This was my initial idea but unfortunately when I used `document.getElementsByTagName('div');` it gives me once again the same error `Uncaught TypeError: Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'.` and I am back to square one. As Dwayne pointed out both `document.querySelectorAll("div");` and `document.getElementsByTagName('div')` are returning a non-live NodeList value. That is why I used `document.body;` instead. – George Smith Jul 06 '17 at 14:32
  • No, that's not what I meant. Your jsfiddle checks childNodes inside the observer callback, which is what I'm talking about. – wOxxOm Jul 06 '17 at 14:38
  • @wOxxOm, do you mean something similar? - [JsFiddle](https://jsfiddle.net/tn2c5n93/) However, it only takes the parent and for some reason skips the children inside the div. Can you please hint me where the mistake in my logic is? Thank you in advance. – George Smith Jul 06 '17 at 22:02
  • @wOxxOm, Thank you very much for the snippet. It was very useful! – George Smith Jul 07 '17 at 16:24