[jquery] jQuery Event : Detect changes to the html/text of a div

I have a div which has its content changing all the time , be it ajax requests, jquery functions, blur etc etc.

Is there a way I can detect any changes on my div at any point in time ?

I dont want to use any intervals or default value checked.

Something like this would do

$('mydiv').contentchanged() {
 alert('changed')
}

This question is related to jquery jquery-ui

The answer is


You are looking for MutationObserver or Mutation Events. Neither are supported everywhere nor are looked upon too fondly by the developer world.

If you know (and can make sure that) the div's size will change, you may be able to use the crossbrowser resize event.


Try the MutationObserver:

browser support: http://caniuse.com/#feat=mutationobserver

_x000D_
_x000D_
<html>_x000D_
  <!-- example from Microsoft https://developer.microsoft.com/en-us/microsoft-edge/platform/documentation/dev-guide/dom/mutation-observers/ -->_x000D_
_x000D_
  <head>_x000D_
    </head>_x000D_
  <body>_x000D_
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>_x000D_
    <script type="text/javascript">_x000D_
      // Inspect the array of MutationRecord objects to identify the nature of the change_x000D_
function mutationObjectCallback(mutationRecordsList) {_x000D_
  console.log("mutationObjectCallback invoked.");_x000D_
_x000D_
  mutationRecordsList.forEach(function(mutationRecord) {_x000D_
    console.log("Type of mutation: " + mutationRecord.type);_x000D_
    if ("attributes" === mutationRecord.type) {_x000D_
      console.log("Old attribute value: " + mutationRecord.oldValue);_x000D_
    }_x000D_
  });_x000D_
}_x000D_
      _x000D_
// Create an observer object and assign a callback function_x000D_
var observerObject = new MutationObserver(mutationObjectCallback);_x000D_
_x000D_
      // the target to watch, this could be #yourUniqueDiv _x000D_
      // we use the body to watch for changes_x000D_
var targetObject = document.body; _x000D_
      _x000D_
// Register the target node to observe and specify which DOM changes to watch_x000D_
      _x000D_
      _x000D_
observerObject.observe(targetObject, { _x000D_
  attributes: true,_x000D_
  attributeFilter: ["id", "dir"],_x000D_
  attributeOldValue: true,_x000D_
  childList: true_x000D_
});_x000D_
_x000D_
// This will invoke the mutationObjectCallback function (but only after all script in this_x000D_
// scope has run). For now, it simply queues a MutationRecord object with the change information_x000D_
targetObject.appendChild(document.createElement('div'));_x000D_
_x000D_
// Now a second MutationRecord object will be added, this time for an attribute change_x000D_
targetObject.dir = 'rtl';_x000D_
_x000D_
_x000D_
      </script>_x000D_
    </body>_x000D_
  </html>
_x000D_
_x000D_
_x000D_


Adding some content to a div, whether through jQuery or via de DOM-API directly, defaults to the .appendChild() function. What you can do is to override the .appendChild() function of the current object and implement an observer in it. Now having overridden our .appendChild() function, we need to borrow that function from an other object to be able to append the content. Therefor we call the .appendChild() of an other div to finally append the content. Ofcourse, this counts also for the .removeChild().

var obj = document.getElementById("mydiv");
    obj.appendChild = function(node) {
        alert("changed!");

        // call the .appendChild() function of some other div
        // and pass the current (this) to let the function affect it.
        document.createElement("div").appendChild.call(this, node);
        }
    };

Here you can find a naïf example. You can extend it by yourself I guess. http://jsfiddle.net/RKLmA/31/

By the way: this shows JavaScript complies the OpenClosed priciple. :)


There is no inbuilt solution to this problem, this is a problem with your design and coding pattern.

You can use publisher/subscriber pattern. For this you can use jQuery custom events or your own event mechanism.

First,

function changeHtml(selector, html) {
    var elem = $(selector);
    jQuery.event.trigger('htmlchanging', { elements: elem, content: { current: elem.html(), pending: html} });
    elem.html(html);
    jQuery.event.trigger('htmlchanged', { elements: elem, content: html });
}

Now you can subscribe divhtmlchanging/divhtmlchanged events as follow,

$(document).bind('htmlchanging', function (e, data) {
    //your before changing html, logic goes here
});

$(document).bind('htmlchanged', function (e, data) {
    //your after changed html, logic goes here
});

Now, you have to change your div content changes through this changeHtml() function. So, you can monitor or can do necessary changes accordingly because bind callback data argument containing the information.

You have to change your div's html like this;

changeHtml('#mydiv', '<p>test content</p>');

And also, you can use this for any html element(s) except input element. Anyway you can modify this to use with any element(s).


DOMSubtreeModified is not a good solution. It's can cause infinite loops if you decide to change the DOM inside the event handler, hence it has been disabled in a number of browsers. MutationObserver will be the answer.

MDN Doc

const onChangeElement = (qSelector, cb)=>{
 const targetNode = document.querySelector(qSelector);
 if(targetNode){
    const config = { attributes: true, childList: false, subtree: false };
    const callback = function(mutationsList, observer) {
        cb($(qSelector))
    };
    const observer = new MutationObserver(callback);
    observer.observe(targetNode, config);
 }else {
    console.error("onChangeElement: Invalid Selector")
 }
}

And you can use it,

onChangeElement('mydiv', function(jqueryElement){
   alert('changed')
})

You can store the old innerHTML of the div in a variable. Set an interval to check if the old content matches the current content. When this isn't true do something.


Use MutationObserver as seen in this snippet provided by Mozilla, and adapted from this blog post

Alternatively, you can use the JQuery example seen in this link

Chrome 18+, Firefox 14+, IE 11+, Safari 6+

// Select the node that will be observed for mutations
var targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
var config = { attributes: true, childList: true };

// Callback function to execute when mutations are observed
var callback = function(mutationsList) {
    for(var mutation of mutationsList) {
        if (mutation.type == 'childList') {
            console.log('A child node has been added or removed.');
        }
        else if (mutation.type == 'attributes') {
            console.log('The ' + mutation.attributeName + ' attribute was modified.');
        }
    }
};

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

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

// Later, you can stop observing
observer.disconnect();

If you don't want use timer and check innerHTML you can try this event

$('mydiv').bind('DOMSubtreeModified', function(){
  console.log('changed');
});

More details and browser support datas are Here.

Attention: in newer jQuery versions bind() is deprecated, so you should use on() instead:

$('body').on('DOMSubtreeModified', 'mydiv', function(){
  console.log('changed');
});

Using Javascript MutationObserver

  //More Details https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
 // select the target node
var target = document.querySelector('mydiv')
// create an observer instance
var observer = new MutationObserver(function(mutations) {
  console.log(target.innerText);   
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);

Since $("#selector").bind() is deprecated, you should use:

$("body").on('DOMSubtreeModified', "#selector", function() {
    // code here
});

You can try this

$('.myDiv').bind('DOMNodeInserted DOMNodeRemoved', function() {

});

but this might not work in internet explorer, haven't tested it


Following code works for me.

$("body").on('DOMSubtreeModified', "mydiv", function() {
    alert('changed');
});

Hope it will help someone :)


Tried some of answers given above but those fires event twice. Here is working solution if you may need the same.

$('mydiv').one('DOMSubtreeModified', function(){
    console.log('changed');
});