Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

parentNode is null with MutationObserver.observe(document.body

Tags:

javascript

I want to track some special tags as UI component, e.g. <color>, <date>, so when such element is created and inserted to DOM, I can convert it to real functional html block.

Here's code, observe addedNodes on document.body.

function handleAddedNodes(nodes) {

    [].forEach.call(nodes, function(node) {

        if (!node.tagName)
            return;

        //how is it possible, node.parentNode is null?????
        if (!node.parentNode) {
            return;
        }
    });
}

var observer = new MutationObserver(function(mutations) {

    mutations.forEach(function(mutation) {

        handleAddedNodes(mutation.addedNodes);
    });
});

observer.observe(document.body, {
    childList : true,
    subtree : true
});

It works fine as expected, but I also found a weird problem: no parentNode for some addedNodes(as "observe(document.body" means addedNodes should be descendants of document.body, right?)

The whole function works as an addon to a big frontend project, I don't know how the project mutate the DOM, set innerHTML or appendChild(too much code here). It also can not be debugged, as observe function is async, like event, no function call stack.

So I just want to know what could cause this, and even better if it can be reproduced with jsFiddle.

Well, seemed jsFiddle can reproduce this,

enter image description here

like image 443
Andrew Avatar asked Dec 16 '13 10:12

Andrew


1 Answers

If an element is added and then immediately (faster than the next setImmediate is triggered) removed to a watched element of a MutationObserver, the observer will notice and add a mutation for both the addedNode and the removedNode - but as you've noticed the referenced element will not have a parent node.

Updated with example See fiddle

With your MutationObserver from op the following code will call handleAddedNodes thrice, once for an element thats been removed and once for an element that was appended to the removed element. The removed element will have no parent while the second element will have a parent.

var body = document.body;
var test = document.createElement("div");
var test2 = document.createElement("span");
body.appendChild(test);//adds childList mutation (addedNodes)
test.appendChild(test2);//adds subtree mutation (addedNodes)
body.removeChild(test);//adds mutation (removedNodes)
like image 84
megawac Avatar answered Nov 04 '22 17:11

megawac