8

I want a certain function to be called whenever another script adds a div to the body.

I tried:

var dom_observer = new MutationObserver(function(mutation) {
    console.log('function called');
});
var container = document.body;
console.log(container);
var config = { attributes: true, childList: true, characterData: true };
dom_observer.observe(container, config);

I tried setting container to document.body (example above) and to document.querySelector('body'). In both cases, console.log() displayed null and I got the following error: TypeError: Argument 1 of MutationObserver.observe is not an object.. The callback function was not called when a div was added to the body.

I tried setting it to document.getElementsByTagName("body")[0] and to document.documentElement.childNodes[1]. In both cases, console.log() displayedundefined and the callback function was still never called.

Mat
  • 833
  • 1
  • 5
  • 20
  • 1
    When are you calling this script ? Is your DOM loaded at that time ? if `console.log(document.body)` outputs `null` it's either that you are not in an HTML document, either that the markup's parsing is only at the ``. Ps : if you're not yet comfortable with DOM parsing and the different load events, delay a little bit your learning of Mutation Observer, chances are great you don't even need it. – Kaiido Jul 15 '17 at 11:51
  • Thank you, that was the solution. I had to put the code inside `jQuery(document).ready(function{…});`. Fixed everything. You could post this as the question answer. – Mat Jul 15 '17 at 11:56

1 Answers1

12

The problem is that you're setting the target as document, and not container. To make sure this is cross-browser compatible, use document.documentElement along with document.body. The following should work:

var dom_observer = new MutationObserver(function(mutation) {
    console.log('function called');
});
var container = document.documentElement || document.body;
console.log(container);
var config = { attributes: true, childList: true, characterData: true };
dom_observer.observe(container, config);

Working JSFiddle

Jacques Marais
  • 2,666
  • 14
  • 33
  • I didn't downvote, but I would presume it's because this doesn't work - as your fiddle even shows – Rory McCrossan Jul 15 '17 at 11:28
  • 1
    @RoryMcCrossan The fiddle does indeed work. See the console when using `document` instead of `container`. I even tested it by adding something to the body afterwards. – Jacques Marais Jul 15 '17 at 11:29
  • You're right, my mistake. I was confused as your fiddle did not call the function as you don't make any amendments to the DOM. – Rory McCrossan Jul 15 '17 at 11:31
  • @RoryMcCrossan I updated the fiddle to add an element to the DOM. – Jacques Marais Jul 15 '17 at 11:33
  • Sorry, I made a mistake copy-pasting my code to StackOverflow. I actually tried this code already, but `console.log` displayed `null` and I got the following error: `TypeError: Argument 1 of MutationObserver.observe is not an object`. I think this is because Firefox doesn't support `document.body`. – Mat Jul 15 '17 at 11:51
  • 1
    @Louis-MarieMatthews See my updated answer. – Jacques Marais Jul 15 '17 at 11:56
  • 1
    Thanks, the problem actually came from the fact my script was called even though the DOM was not completely loaded. Putting the code inside `jQuery(document).ready(function{…});` solved everything. However I was wrong, Firefox supports `document.body`. Using your updated code actually prevents the script from working. – Mat Jul 15 '17 at 11:58
  • 1
    Oh, alright then. – Jacques Marais Jul 15 '17 at 11:59
  • 1
    `document` is a valid node for `MutationObserver.observe()`. The OP's problem was that they weren't using `subtree:true` in the observer. – Eli Grey Aug 29 '19 at 18:20