29

Is there a way in jquery to listen for a change to a node's class and then take some action on it if the class changes to a specific class? Specifically, I'm using the jquery tools tabs plugin with the slideshow and as the slideshow is playing, I need to be able to detect when the focus is on a particular tab/anchor so that I can unhide a specific div.

In my specific example, I need to know when:

<li><a class="nav-video" id="nav-video-video7" href="#video7-video">Video Link 7</a></li>

changes to the following with the class "current" added:

<li><a class="nav-video" id="nav-video-video7 current" href="#video7-video">Video Link 7</a></li>

Then I want to unhide a div at that moment.

Thanks!

Dude Bro
  • 1,152
  • 1
  • 10
  • 13
Snazawa
  • 327
  • 1
  • 3
  • 8
  • 1
    This [questions][1] answers can help. [1]: http://stackoverflow.com/questions/6034161/how-can-i-detect-when-an-html-elements-class-changes – Bhanu Krishnan Jul 22 '11 at 04:10

4 Answers4

28

You can bind the DOMSubtreeModified event. I add an example here:

$(document).ready(function() {
  $('#changeClass').click(function() {
    $('#mutable').addClass("red");
  });

  $('#mutable').bind('DOMSubtreeModified', function(e) {
    alert('class changed');
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="mutable" style="width:50px;height:50px;">sjdfhksfh
  <div>
    <div>
      <button id="changeClass">Change Class</button>
    </div>

http://jsfiddle.net/hnCxK/13/

double-beep
  • 5,031
  • 17
  • 33
  • 41
Wood
  • 1,766
  • 1
  • 12
  • 10
  • 7
    [DOMSubtreeModified](https://developer.mozilla.org/en-US/docs/Web/Events/DOMSubtreeModified) is deprecated, use [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) instead. – Fangxing Apr 26 '18 at 08:19
  • See my answer below for `MutationObserver` example. – codeMonkey Mar 30 '20 at 21:28
6

I know this is old, but the accepted answer uses DOMSubtreeModified, which has now been deprecated for the MutationObserver. Here's an example using jQuery (test it out here):

// Select the node that will be observed for mutations
let targetNode = $('#some-id');

// Options for the observer (which mutations to observe)
const config = { attributes: true, childList: false, subtree: false, attributeFilter: ['class'] };

// Callback function to execute when mutations are observed
const callback = function(mutationsList, observer) {
    for (let mutation of mutationsList) {
        if (mutation.attributeName === "class") {
            var classList = mutation.target.className;
            // Do something here with class you're expecting
            if(/red/.exec(classList).length > 0) {
                console.log('Found match');
            }
        }
    }
};

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode[0], config);

// Later, you can stop observing
observer.disconnect();
codeMonkey
  • 4,134
  • 2
  • 31
  • 50
3

Here are some other finds that might provide a solution:

  1. Most efficient method of detecting/monitoring DOM changes?
  2. How can I detect when an HTML element’s class changes?
  3. Monitoring DOM Changes in JQuery

And as it was suggested in #2, why not make current a class that is added, rather than a ID, and have the following CSS handle the show/hide action.

<style type='text/css>
    .current{display:inline;}
    .notCurrent{display:none;}
</style>

Might also be worth it to look into .on() in jquery.

Community
  • 1
  • 1
JSuar
  • 21,056
  • 4
  • 39
  • 83
  • 2
    Google brought me here. I looked at ".on()" but it wasn't clear which event might trigger when a class is added to an element. I'm in a similar situation as the OP, and needed to trigger when a class is added, but I can't bind to the original click event because the plugin calls preventDefault on the click event. – Dustin Graham Nov 14 '12 at 18:03
  • It's been a while since I posted this question and quite frankly I forget how I handled it. Using CSS to hide/unhide a div would be the obvious solution but I'm pretty sure that I must have had some additional things going on that prevented me from keeping it that simple. In any case, I chose the @jsuar solution since it included some helpful links. – Snazawa Jul 29 '13 at 00:11
0

With anything like this you have essentially two options, callbacks or polling.

Since you possibly can't get an event to be triggered when the DOM mutates in this way (reliably across all platforms) you may have to resort to polling. To be a bit nicer about it, you could try using the requestAnimationFrame api rather than just using something like setInterval natively.

Taking the most basic approach (i.e. using setInterval and assuming jQuery) you might try something like this:

var current_poll_interval;
function startCurrentPolling() {
  current_poll_interval = setInterval(currentPoll, 100);
}
function currentPoll() {
  if ( $('#nav-video-7').hasClass('current') ) {
    // ... whatever you want in here ...
    stopCurrentPolling();
  }
}
function stopCurrentPolling() {
  clearInterval(current_poll_interval);
}
pete otaqui
  • 1,432
  • 14
  • 11