Search code examples
javascriptgoogle-chromemutation-observers

Chrome MutationObserver not activated on some elements


I am having a problem where MutationObserver does not work on some elements.

I extracted a 'simple' example:

In chrome load news.google.com and open the debugger console

Paste this code:

for (elem of document.getElementsByTagName('*')) elem.style.backgroundColor = 'red';

let observer;

function mutationObserve() {
    observer.observe(document, { childList: true, subtree:true, attributes: true });
}

function mutationDisconnect() {
    observer.disconnect();
}

function handleMutation(mutations) {
    mutationDisconnect();
    mutations.forEach(mutation => {
        for (elem of mutation.addedNodes) {
            elem.style.backgroundColor = 'green';
            for (innerElem of elem.getElementsByTagName('*')) {
                innerElem.style.backgroundColor = 'green';
            }
        }
    });
    mutationObserve();
}

observer = new MutationObserver(handleMutation);
mutationObserve();

What this does is:

  • first change all elements background to red
  • set a mutation observer to change all modified element's background to green

Now change heading (ie, click on business)

What happens is that you get some elements in red (unmodified)
and some elements in green (modified and changed by the MutationObserver)
and some in white because they are have the background defined in classes (ie, post bodies)

But also a menu strip at the top (containing headlines/local/etc) becomes white.

If I inspect I see it now has

<div class="gb_wd gb_Wd" style="background-color: rgb(255, 255, 255);">

So it changed it's style (background-color went from red to white) but was not 'catched' by the mutation observer.

Is this a bug ? or am I doing something wrong ? how can I get MutationObserver to observe such changes ?

Thx!


Solution

  • Attribute mutations, such as style, don't add nodes so you need to recolor mutation.target:

    for (const mutation of mutations) {
      if (mutation.type == 'attributes')
        mutation.target.style.backgroundColor = 'yellow';
      for (const elem of mutation.addedNodes) {
        if (elem.nodeType != Node.ELEMENT_NODE)
          continue;
        elem.style.backgroundColor = 'green';
        for (const innerElem of elem.getElementsByTagName('*')) {
          innerElem.style.backgroundColor = 'green';
        }
      }
    }