'MutationObserver not firing when setting display to none

I have a node called 'cover' that gets set to visible or not visible when the ajax layer wants to hide/show it based on it being our veil. But we want our veil to be more than just a single node going visible or invisible. So I wrote a MutationObserver to watch for the change and do the extra work. This works fine when the node gets changed to display: block. It does NOT fire when it changes to display: none.

You can see the observer below, and between this and breakpoints, I am confident that it is never called on display:none changes. And yes, I can see that change has been made in the watch list. This happens in both IE and Chrome.

Is this expected? I didn't expect it. But if so, how can I get that display:none event?

The call to start the observer:

veilObserver.observe(cover, { attributes: true, childList: false, subtree: false });

The observer:

const veilObserver = new MutationObserver(function(mutationsList, observer) {
console.log("MutationObserver enter");
var cover = document.getElementById('cover');

if(cover) {
    console.log("MutationObserver cover");
    if(cover.style.display == 'none') {
        console.log("MutationObserver closing");
        closeVeil();
    } else if(cover.style.display == 'block') {
        openVeil();
    } else {
        //this should never happen, but if it does, we want to make sure the veil is closed because we don't know whether it should be open or
        //closed and I'd rather default to open so the user isn't locked forever. 
        console.log('Mutation!!! but display not recognized: ' + cover.style.display);
        closeVeil();
    }
} else {
    console.log("MutationObserver disconnecting");
    //this implies the page lacks the required HTML.  Disconnect the observer and don't both them again.
    veilObserver.disconnect();
}

});



Solution 1:[1]

If your having trouble determining which parent to observe for attribute changes, you can observe all attribute changes on the document, filter irrelevant changes as much as possible, and then check if your element is visible.

var observer;
observer = new MutationObserver(function(mutations) {
    let cover = document.getElementById('cover')
    if (!cover) observer.disconnect()
    if (!isVisible(cover)) console.log("closing"); 
    else console.log("opening")
});
// main diffrence is the target node to listen to is now document.body
observer.observe(document.body, { 
    attributes: true,
    attributeFilter: ['style'],
    subtree: true
});
function isVisible(element) { return (element.offsetWidth > 0 && element.offsetHeight > 0) }

Solution 2:[2]

Copied this from the docs and tailored it to your code.

You should try observing the parent element of #cover. That way any mutations inside of that element will be observed.

    // Select the node that will be observed for mutations
    const targetNode = document.getElementById(/* The parent element of #cover */);

    // Any changes inside this div will be observed.

    // Options for the observer (which mutations to observe)
    const config = { attributes: true, childList: true, subtree: true };

    // Callback function to execute when mutations are observed
    const callback = function(mutationsList, observer) {
        // Use traditional 'for loops' for IE 11
        for(let mutation of mutationsList) {
            if (mutation.type === 'childList') {
                console.log('A child node has been added or removed.');
                // Check if the element that changed was #cover
                console.log(mutation.target.id === 'cover');

                if(mutation.target.id === 'cover') {
                  let id = mutation.target.id;
                  if(document.getElementById(id).style.display === 'none') {
                    // Do something
                    // disconnect perhaps.
                  }
                }
                
                
            }
            else if (mutation.type === 'attributes') {
                // If the style is inline this may work too. 
                console.log('The ' + mutation.attributeName + ' attribute was modified.');
                console.log(mutation.attributeName === 'style');
                
                let id = mutation.target.id;

                if(document.getElementById(id).style.display === 'none') {
                  // Do something
                  // disconnect perhaps.
                }
            }
        }
    };

    // Create an observer instance linked to the callback function
    const observer = new MutationObserver(callback);

    // Start observing the target node for configured mutations
    observer.observe(targetNode, config);

    // Later, you can stop observing
    observer.disconnect();

https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Spankied
Solution 2