Search code examples
javascriptfirefoxgreasemonkeymutation-observers

MutationObserver error : How could I wait for the creation of an element?


I'm trying to make a Greasemonkey script to add a button in a Facebook page. But I need to wait for the creation of an element to add the button on it.
I'm trying to use MutationObserver (As suggested here) to do it but there is an error.

function init() {
    console.log('Launched : ' + launched);
    if (!launched) {
        launched = true;
        main();
    }
}
console.log('barfoo');

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        if (!mutation.addedNodes) return;
        console.log(mutation.addedNodes.type());
        for (var i = 0; i < mutation.addedNodes.length; i++) {
            if (mutation.addedNodes[i].matches('div[class="pam _5shk uiBoxWhite bottomborder"]')) {
                console.log('init');
                init();
            }
        }
    })
});
console.log('bar');

try {
    observer.observe(document.body, {
        childlist: true,
        subtree: true,
        attributes: false,
        characterData: false,
    });
} catch (error) {
    console.log(error);
}
console.log('foobar');

But I got the following logs:

barfoo
bar
DOMException [TypeError: "The expression cannot be converted to return the specified type."
code: 0
nsresult: 0x805b0034
location: file:///home/vmonteco/.mozilla/firefox/f3xgmo8e.default/gm_scripts/Facebook_cleaner/Facebook_cleaner.user.js:230] Facebook_cleaner.user.js:239:3
foobar

What is the cause of this error? How could I fix this?

If the element is created before the execution of my script, will the MutationObserver still be triggered? (IE, if the element already exists when I create the MutationObserver).

NB: I tried to use $(document).ready(), but it's triggered before the creation of the element I want to add the button to.

NB-bis: I didn't post the whole script.


Solution

  • That error message use totally vague unfortunately, but you have a typo:

    observer.observe(document.body, {
      childlist: true,
      subtree: true,
      attributes: false,
      characterData: false,
    });
    

    should be

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

    e.g. childlist => childList

    In this case, running your same code in Chrome gives a more helpful message than "cannot be converted to return the specified type". It says

    The options object must set at least one of 'attributes', 'characterData', or 'childList' to true.