Search code examples
javascriptjquerymutation-observers

How to trigger an event when "display: none" is removed?


I apologize if this was answered previously, I couldn't find it using the search.

I have to tag 4 elements to fire off an event when they are unhidden ("display: none" is removed). I think a mutationObserver is the right way to go, but am having trouble filtering to just the event I need.

Anyone have experience doing this?

Edit: Unfortunately, we do not have access to the script actually unhiding the elements. They are owned and protected by another team. The only thing we can key on is when the element is unhidden.

I was trying to figure out how to edit this for my needs.

    // Blocker is the element that has a changing display value
var blocker  = document.querySelector( '#blocker' );
// Trigger changes the display value of blocker
var trigger  = document.querySelector( '#trigger' );
// Our mutation observer, which we attach to blocker later
var observer = new MutationObserver( function( mutations ){
    mutations.forEach( function( mutation ){
        // Was it the style attribute that changed? (Maybe a classname or other attribute change could do this too? You might want to remove the attribute condition) Is display set to 'none'?
        if( mutation.attributeName === 'style' && window.getComputedStyle( blocker ).getPropertyValue( 'display' ) !== 'none'
          ){
            alert( '#blocker\'s style just changed, and its display value is no longer \'none\'' );
        }
    } );
} );

// Attach the mutation observer to blocker, and only when attribute values change
observer.observe( blocker, { attributes: true } );

// Make trigger change the style attribute of blocker
trigger.addEventListener( 'click', function(){
    blocker.removeAttribute( 'style' );
}, false );

Solution

  • The code below works if display:none is set via the style attribute. If you also need to handle the case where it's shown/hidden via toggling a class, then use the ResizeObserver approach as shown in BenVida's answer.

    var blocker  = document.querySelector('#blocker');
    var previousValue = blocker.style.display;
    
    var observer = new MutationObserver( function(mutations){
        mutations.forEach( function(mutation) {
            if (mutation.attributeName !== 'style') return;
            var currentValue = mutation.target.style.display;
            if (currentValue !== previousValue) {
               if (previousValue === "none" && currentValue !== "none") {
                 console.log("display none has just been removed!");
               }
    
               previousValue = mutation.target.style.display;
            }
        });
    });
    
    
    observer.observe(blocker, { attributes: true });
    

    Basically we get the default value set in the style attribute (if there is any) - this is stored in previousValue; Then we leave the code, but we make some differences in the loop. Firstly we check whether the style was changed in the target. Then we get the current display value in the target's style attribute. Next step is to compare those values. If previousValue was "none" and now it's something else, this means the display: none was unset. However you must note that it listens only for this specific change. If you don't need to listen for "none" then you may omit it.

    You can use it in your code - I didn't write your entire code on purpose, so feel free to add your event listener on target.