Search code examples
javascripteventsmutation-observers

MutationObserver with specific mutations


I am currently trying to use the MutationObserver API to fire a message (which later will be functions) based on class change of an element.

I'm currently firing a log on mutation change, but I'm assuming there are mutations such as DOM position etc that are firing. Is there a way to make the MutationObserver only look for specific attributes in this case the class?

As primarily a Drupal developer I'm used to using jQuery and that's why I have the classList function as I like chaining.

Here is my code:

var foo = document.getElementById("foo");
var wrapper = document.getElementById("wrapper");

var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
        if (mutation.attributeName === "class") {
        	var attributeValue = mutation.target.getAttribute(mutation.attributeName);
            console.log("Class attribute changed to:", attributeValue);
        }
    });
});

function classList(el) {
  var list = el.classList;
  return {
      add: function(c) { 
         if (!list.contains(c)){
            console.log('Contains: '+list.contains(c));
      	    list.add(c); 
         }
         return this;
      },
      remove: function(c) { 
         if (!list.contains(c)){ 
            list.remove(c); 
         }
         return this; 
      }
  };
}

observer.observe(foo,  {
    attributes: true
});

wrapper.addEventListener("scroll",function(){
    classList(foo).add('red').remove('yellow');
    if(wrapper.scrollTop > 500){
         classList(foo).add('yellow').remove('red');
    }
});
#wrapper {
  height: 200px;
  overflow: scroll;
}
#foo {
  height: 1000px;
}
<div id="wrapper">
   <div id="foo">Element</div>
</div>


Solution

  • Although @wOxxOm answered my question(negligence) in his comment, I applied the functionaily and realised that I no longer needed a forEach as I was only expecting a singular attribute, so the finished(test) code looks like:

    var foo = document.getElementById("foo");
    var wrapper = document.getElementById("wrapper");
    
    var observer = new MutationObserver(function(mutation) {
        console.log('Current class:' + mutation[0].target.className);
    });
    
    observer.observe(foo, {
        attributes: true,
        attributeFilter: ['class']
    });
    
    wrapper.addEventListener("scroll",function(){
        if(wrapper.scrollTop > 500){
            if(!foo.classList.contains('yellow')){
               foo.classList.add('yellow');
               foo.classList.remove('red');
            }
        } else {
            if(!foo.classList.contains('red')){
               foo.classList.add('red');
               foo.classList.remove('yellow');
            }
        }
    });
    #wrapper {
      height: 200px;
      overflow: scroll;
    }
    #foo {
      height: 1000px;
    }
    <div id="wrapper">
       <div id="foo">Element</div>
    </div>

    I have tidied up the mutation observer to find the class name. I removed my function to allow me to chain the class elements, as I came across an issue where it was triggering the mutation even when the class was not changed, just because the element was being returned.