Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any way to find out whether a MutationObserver is disconnected or observing?

It appears that this shows the full list of methods.

Obviously it's not that difficult to find a way around this... but for the sake of elegance there should be a method isConnected, shouldn't there?

like image 469
mike rodent Avatar asked Sep 01 '17 18:09

mike rodent


People also ask

How do you stop a mutation observer?

disconnect() The MutationObserver method disconnect() tells the observer to stop watching for mutations. The observer can be reused by calling its observe() method again.

How can you tell if a element is removed from DOM?

We can detect whether an element has been removed DOM using the MutationObserver object. MutationObserver provides the ability to observe for changes being made to the DOM tree.

Which of the following methods are available to stop observing DOM changes?

The observer object will call the resolve() function once the element is available and stop observing the DOM tree.

When would you use a mutation observer?

MutationObserver can react to changes in DOM – attributes, text content and adding/removing elements. We can use it to track changes introduced by other parts of our code, as well as to integrate with third-party scripts.


1 Answers

If one would really want to know the status of MutationObserver object instance, then a way to get this would be the creation of a new object class from it in a composition style (JSFiddle example):

// to keep actual working methods of the class out of the object's instance whenever possible
// is a good practice, but since ECMAScript2015 (ES2015, ES6) does not support private methods
// (though does support private variables with "var" in constructors), IIFE (Immediately-invoked
// function expression) has to be used to encapsulate, isolate the full class definition:
let UpgradedMutationObserver = (function() 
{
        // private variable/property to store the instance's current status; WeakMap is used to improve memory 
        // management as it sheds its value pairs as soon as the instance is not reference any more:
  const _targetsArrayWeakMap = new WeakMap(), // new WeakMap([[this, []]]) would not work as "this" here is a window object
        // private method-function wrapper that provides access for the object's instance to class prototype
        // methods as well as to an earlier-declared private variable;
        // this wrapper is designed as a function factory as it returns functions that get assigned to the object
        // instance's public methods:
        _callPrototypeMethod = function(prototypeMethod, instance, args)
        {
          // actual type of the private variable/property is set here; runs only once:
          if (typeof _targetsArrayWeakMap.get(instance) === 'undefined')
          {
            _targetsArrayWeakMap.set(instance, []);
          } 
          return function()
          {
            const returnedObject = Object.getPrototypeOf(instance)[prototypeMethod](instance, _targetsArrayWeakMap.get(instance), ...arguments);
            _targetsArrayWeakMap.set(instance, returnedObject.privateVariable);
            return returnedObject.returnValue;
          }
        };
  class UpgradedMutationObserver
  {
    constructor(callback)
    {
      // an arrow function version of the way to attach the object's instance would not need .bind(this)
      // as there is no own "this" in arrow functions, "this" would mean the instance of the object
      this.MutationObserver = new MutationObserver(function( ...args)
      {
        return callback( ...args, this);
      }.bind(this)); 
      this.observe = _callPrototypeMethod('observe', this, arguments); // bind(this);
      this.disconnect = _callPrototypeMethod('disconnect', this, arguments); //.bind(this);
      this.isConnected = _callPrototypeMethod('isConnected', this, arguments); //.bind(this);
      // ... other standard methods like takeRecords() can also taken care of, if necessary
    }
    observe(instance, targetsArray, targetObserve, optionsObserve)
    { 
      // many targets can be observed, though callback function is always the same
      // for the same instance of (Upgraded)MutationObserver:
      instance.MutationObserver.observe(targetObserve, optionsObserve); 
      // before adding targetObserve to the list of observed,
      // it is checked that it exists (at least for now):
      if (document.contains(targetObserve))
      {
        targetsArray.push(targetObserve);
      }
      return {privateVariable: targetsArray};
    }
    disconnect(instance, targetsArray)
    { 
      // the method stops observation of all targets at once
      instance.MutationObserver.disconnect();
      targetsArray = [];
      return {privateVariable: targetsArray};
    }
    isConnected(instance, targetsArray, targetToCheck)
    {
      // in case of observed nodes removed from DOM (destroyed), they are filtered out:
      targetsArray = targetsArray.filter(function(e)
      {
        return document.contains(e);
      });
      // maximum versatily of return results is provided 
      // all while maintaining false/"truthy" quasi-boolean dichotomy:
      return {
                privateVariable: targetsArray,
                returnValue: targetsArray.length == 0
                ? false
                : (targetToCheck
                   ? targetsArray.includes(targetToCheck)
                   : targetsArray)
             };
    }
  }
  return UpgradedMutationObserver;
})();  

console.log('UpgradedMutationObserver: ____________________________________________________________');
const observer = new UpgradedMutationObserver(function(mutationsList, observer)
{
  console.log('UpgradedMutationObserver callback: processing of an added node', mutationsList, observer);
});
console.log('UpgradedMutationObserver initialized as "observer": ', observer);
console.log('UpgradedMutationObserver: observer.isConnected(): ', observer.isConnected()); 

console.log('UpgradedMutationObserver: observer.observe(document.documentElement, {childList: true, subtree: true})...'); 
observer.observe(document.documentElement, {childList: true, subtree: true});

// logs "Array [ html....]"
console.log('UpgradedMutationObserver: observer.isConnected(): ', observer.isConnected()); 

console.log('UpgradedMutationObserver: observer.observe(document.body, {childList: true, subtree: true})...'); 
observer.observe(document.body, {childList: true, subtree: false});

// logs "Array [ html. ..., body. ...]"
console.log('UpgradedMutationObserver: observer.isConnected(): ', observer.isConnected()); 

// logs "true":
console.log('UpgradedMutationObserver: observer.isConnected(document.documentElement): ', observer.isConnected(document.documentElement)); 

var div = document.querySelector('div'), childDiv, i;
for (i = 1; i < 5; i++)
{
  setTimeout(function()
  {
    if (this < 4)
    {
      childDiv = document.createElement('div');
      div.appendChild(childDiv);
      console.log("a child DIV is added after " + this + "s delay for UpgradedMutationObserver to discover");
    }
    else
    {
      console.log('UpgradedMutationObserver: observer.disconnect()...'); 
      observer.disconnect();
      // logs "false" as nothing is observed:
      console.log('UpgradedMutationObserver: observer.isConnected(): ', observer.isConnected()); 
    }
  }.bind(i), i * 1000);
}

like image 149
DDRRSS Avatar answered Oct 12 '22 14:10

DDRRSS