Is There a JavaScript/Jquery Dom Change Listener

Is there a JavaScript / jQuery DOM change listener?

For a long time, DOM3 mutation events were the best available solution, but they have been deprecated for performance reasons. DOM4 Mutation Observers are the replacement for deprecated DOM3 mutation events. They are currently implemented in modern browsers as MutationObserver (or as the vendor-prefixed WebKitMutationObserver in old versions of Chrome):

MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var observer = new MutationObserver(function(mutations, observer) {
// fired when a mutation occurs
console.log(mutations, observer);
// ...
});

// define what element should be observed by the observer
// and what types of mutations trigger the callback
observer.observe(document, {
subtree: true,
attributes: true
//...
});

This example listens for DOM changes on document and its entire subtree, and it will fire on changes to element attributes as well as structural changes. The draft spec has a full list of valid mutation listener properties:

childList

  • Set to true if mutations to target's children are to be observed.

attributes

  • Set to true if mutations to target's attributes are to be observed.

characterData

  • Set to true if mutations to target's data are to be observed.

subtree

  • Set to true if mutations to not just target, but also target's descendants are to be observed.

attributeOldValue

  • Set to true if attributes is set to true and target's attribute value before the mutation needs to be recorded.

characterDataOldValue

  • Set to true if characterData is set to true and target's data before the mutation needs to be recorded.

attributeFilter

  • Set to a list of attribute local names (without namespace) if not all attribute mutations need to be observed.

(This list is current as of April 2014; you may check the specification for any changes.)

jQuery: How to listen for DOM changes?

My best guess is that you want to listen to DOM mutation events.
You can do that by DOM mutation event as any normal javascript event such as a mouse click.

Refer to this : W3 MutationEvent

Example:

$("element-root").bind("DOMSubtreeModified", "CustomHandler");

Detect changes in the DOM

2015 update, new MutationObserver is supported by modern browsers:

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

If you need to support older ones, you may try to fall back to other approaches like the ones mentioned in this 5 (!) year old answer below. There be dragons. Enjoy :)


Someone else is changing the document? Because if you have full control over the changes you just need to create your own domChanged API - with a function or custom event - and trigger/call it everywhere you modify things.

The DOM Level-2 has Mutation event types, but older version of IE don't support it. Note that the mutation events are deprecated in the DOM3 Events spec and have a performance penalty.

You can try to emulate mutation event with onpropertychange in IE (and fall back to the brute-force approach if non of them is available).

For a full domChange an interval could be an over-kill. Imagine that you need to store the current state of the whole document, and examine every element's every property to be the same.

Maybe if you're only interested in the elements and their order (as you mentioned in your question), a getElementsByTagName("*") can work. This will fire automatically if you add an element, remove an element, replace elements or change the structure of the document.

I wrote a proof of concept:

(function (window) {
var last = +new Date();
var delay = 100; // default delay

// Manage event queue
var stack = [];

function callback() {
var now = +new Date();
if (now - last > delay) {
for (var i = 0; i < stack.length; i++) {
stack[i]();
}
last = now;
}
}

// Public interface
var onDomChange = function (fn, newdelay) {
if (newdelay) delay = newdelay;
stack.push(fn);
};

// Naive approach for compatibility
function naive() {

var last = document.getElementsByTagName('*');
var lastlen = last.length;
var timer = setTimeout(function check() {

// get current state of the document
var current = document.getElementsByTagName('*');
var len = current.length;

// if the length is different
// it's fairly obvious
if (len != lastlen) {
// just make sure the loop finishes early
last = [];
}

// go check every element in order
for (var i = 0; i < len; i++) {
if (current[i] !== last[i]) {
callback();
last = current;
lastlen = len;
break;
}
}

// over, and over, and over again
setTimeout(check, delay);

}, delay);
}

//
// Check for mutation events support
//

var support = {};

var el = document.documentElement;
var remain = 3;

// callback for the tests
function decide() {
if (support.DOMNodeInserted) {
window.addEventListener("DOMContentLoaded", function () {
if (support.DOMSubtreeModified) { // for FF 3+, Chrome
el.addEventListener('DOMSubtreeModified', callback, false);
} else { // for FF 2, Safari, Opera 9.6+
el.addEventListener('DOMNodeInserted', callback, false);
el.addEventListener('DOMNodeRemoved', callback, false);
}
}, false);
} else if (document.onpropertychange) { // for IE 5.5+
document.onpropertychange = callback;
} else { // fallback
naive();
}
}

// checks a particular event
function test(event) {
el.addEventListener(event, function fn() {
support[event] = true;
el.removeEventListener(event, fn, false);
if (--remain === 0) decide();
}, false);
}

// attach test events
if (window.addEventListener) {
test('DOMSubtreeModified');
test('DOMNodeInserted');
test('DOMNodeRemoved');
} else {
decide();
}

// do the dummy test
var dummy = document.createElement("div");
el.appendChild(dummy);
el.removeChild(dummy);

// expose
window.onDomChange = onDomChange;
})(window);

Usage:

onDomChange(function(){ 
alert("The Times They Are a-Changin'");
});

This works on IE 5.5+, FF 2+, Chrome, Safari 3+ and Opera 9.6+

jQuery watch for domElement changes?

The most effective way I've found is to bind to the DOMSubtreeModified event. It works well with both jQuery's $.html() and via standard JavaScript's innerHTML property.

$('#content').bind('DOMSubtreeModified', function(e) {
if (e.target.innerHTML.length > 0) {
// Content change handler
}
});

http://jsfiddle.net/hnCxK/

When called from jQuery's $.html(), I found the event fires twice: once to clear existing contents and once to set it. A quick .length-check will work in simple implementations.

It's also important to note that the event will always fire when set to an HTML string (ie '<p>Hello, world</p>'). And that the event will only fire when changed for plain-text strings.

Efficiently detect DOM change in single page application

MutationObserver is probably your best bet. Before MutationObserver, there were Mutation events, but these are now deprecated and not recommended.

Another (arguably poor) option would be to use a setTimeout and periodically check the DOM for changes. But this would require you to write a function to get the nodes you want to check and compare the current value with the old value. This wouldn't be as efficient, since you'd be checking the nodes every X milliseconds, even if there are no changes.

You should be able to write your code in such a way that an infinite loop does not occur. If you are getting an infinite loop, you should add that code to your question above.

As far as performance goes, since MutationObserver will give you old and new values, you could compare these values instead of traversing the entire DOM. For example, something like this:

let observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
let oldValue = mutation.oldValue;
let newValue = mutation.target.textContent;
if (oldValue !== newValue) {
// do something
}
});
});

observer.observe(document.body, {
characterDataOldValue: true,
subtree: true,
childList: true,
characterData: true
});

Detect element content changes with jQuery

These are mutation events.

I have not used mutation event APIs in jQuery, but a cursory search led me to this project on GitHub. I am unaware of the project's maturity.



Related Topics



Leave a reply



Submit