Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make one MutationObserver listen for changes on multiple elements?

Tags:

jquery

I have implemented the following code for observing changes in class:

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

observer.observe(document.querySelector(".xxx"), {
  attributes: true
});  });

JSFiddle link: https://jsfiddle.net/8Lfj0ev3/

Ideally, I want this to listen for changes in all elements with class 'xxx'. But it is only listening to first element with xxx class and ignoring others. How can I fix this?

like image 224
The One Avatar asked Jul 07 '26 06:07

The One


1 Answers

Two ways to address this:

Multiple observe calls

You can call observe multiple times to watch multiple elements:

$(".xxx").each(function() {
  observer.observe(this, {
    attributes: true
  });
});

Live Example:

$(document).ready(function() {
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      if (mutation.attributeName === "class") {
        var attributeValue = $(mutation.target).prop(mutation.attributeName);
        console.log("Class attribute changed to:", attributeValue);
      }
    });
  });
  
  $(".xxx").each(function() {
    observer.observe(this, {
      attributes: true
    });
  });
});

setTimeout(function() {
  $(".d1").addClass("x1");
}, 800);
setTimeout(function() {
  $(".d2").addClass("x2");
}, 1600);
setTimeout(function() {
  $(".d3").addClass("x3");
}, 2400);
<div class="d1 xxx"></div>

<div class="d2 xxx"> </div>

<div class="d3 xxx"> </div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Watch container's subtree

But another option is to watch the subtree of the nearest container they're all in and then only pay attention to changes if they occurred within a .xxx element:

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

observer.observe(document.body, {                                  // ***
  attributes: true,
  subtree: true                                                    // ***
});

Live Example:

$(document).ready(function() {
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      if (mutation.attributeName === "class") {
        var $target = $(mutation.target);
        if ($target.hasClass("xxx")) {
          var attributeValue = $target.prop(mutation.attributeName);
          console.log("Class attribute changed to:", attributeValue);
        }
      }
    });
  });
  
  observer.observe(document.body, {
    attributes: true,
    subtree: true
  });
});

setTimeout(function() {
  $(".d1").addClass("x1");
}, 800);
setTimeout(function() {
  $(".d2").addClass("x2");
}, 1600);
setTimeout(function() {
  $(".d3").addClass("x3");
}, 2400);
<div class="d1 xxx"></div>

<div class="d2 xxx"> </div>

<div class="d3 xxx"> </div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

In that example the nearest container is document.body, but of course in your real situation there may be something closer to the elements.

like image 81
T.J. Crowder Avatar answered Jul 08 '26 19:07

T.J. Crowder