Question

I am trying to get the information on change in element state using Javascript MutationObserver
to get what was the state of the element before the change then check what is current state and based on that make some decisions.

Basically I am trying implement onVisibilityChanged event.

I am capturing any change on elements that I care about, then I do check if they are visible or not. Then if visibility is different to what it was broadcast visibilityChanged.
I know workaround I could do, since I am getting changes that happened I could create clone of element (MutationEvent[0].target) and revert apply all changes then check if clone is visible, this however sounds 'hacky' and inefficient so I was wondering is there a way of capturing element right before mutation happened. I do understand it's a long-shot since MutationObserver is fired after all changes happened and it's like travelling in time, yet I am all ears for your suggestions.

var observer = new MutationObserver(function(mutations) {
var itemFromThePast = mutations[0].MagicTimeMachine().GetMeTheItemBeforeItWasChanged; // this is the line that is missing
if ($(itemFromThePast).is(":visible") != $(mutations[0].target).is(":visible"))
      {
       console.log('I win!');
      }
    
});
var targets = $('.ui-collapsible-content');

$.each(targets, function(i,target){
observer.observe(target, { attributes: true, childList: false, characterData : true,     characterDataOldValue : true });
});
Was it helpful?

Solution

One way to do this.
Works only on visibility changes that are made by class change.

var observer = new MutationObserver(function(mutations) {
    var clone = $(mutations[0].target).clone();
    clone.removeClass();
    for(var i = 0; i < mutations.length; i++){
        clone.addClass(mutations[i].oldValue);
    }
    $(document.body).append(clone);
    var cloneVisibility = $(clone).is(":visible");
    $(clone).remove();
    if (cloneVisibility != $(mutations[0].target).is(":visible")){
        var visibilityChangedEvent = document.createEvent('Event');
        visibilityChangedEvent.initEvent('visibilityChanged', true, true);
        mutations[0].target.dispatchEvent(visibilityChangedEvent);
    }
});

var targets = $('.ui-collapsible-content');
$.each(targets, function(i,target){
    target.addEventListener('visibilityChanged', function(){ console.log('Kaboom babe');});
    observer.observe(target, { attributes: true, attributeFilter : ['class'], childList: false, attributeOldValue: true });
});

OTHER TIPS

Nowadays there are better alternatives. As a modern approach, I would suggest the Intersection Observer API, with some good examples on the following pages. This API is designed to be notified when an element is not, partially or fully visible.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top