Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<h2>2015 update, new <a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver" rel="noreferrer"><code>MutationObserver</code></a> is supported by modern browsers:</h2> <p><em>Chrome 18+, Firefox 14+, IE 11+, Safari 6+</em> </p> <p>If you need to support older ones, you may try to fall back to other approaches like the ones mentioned in this <em>5</em> (!) year old answer below. There be dragons. Enjoy :) </p> <hr> <p>Someone else is changing the document? Because if you have full control over the changes you just need to create your own <code>domChanged</code> API - with a function or custom event - and trigger/call it everywhere you modify things. </p> <p>The <strong>DOM Level-2 has <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-eventgroupings-mutationevents" rel="noreferrer">Mutation event types</a></strong>, but older version of IE don't support it. Note that the mutation events are <a href="http://www.w3.org/TR/DOM-Level-3-Events/#events-mutationevents" rel="noreferrer">deprecated in the DOM3 Events spec</a> and have a <a href="https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events" rel="noreferrer">performance penalty</a>.</p> <p>You can try to emulate mutation event with <strong><code>onpropertychange</code> in IE</strong> (and fall back to the brute-force approach if non of them is available).</p> <p>For a <em>full</em> 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.</p> <p>Maybe if you're only interested in the elements and their order (as you mentioned in your question), a <code>getElementsByTagName("*")</code> can work. This will fire automatically if you add an element, remove an element, replace elements or change the structure of the document. </p> <p>I wrote a proof of concept:</p> <pre><code>(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 &gt; delay) { for (var i = 0; i &lt; 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 &lt; 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); </code></pre> <p>Usage:</p> <pre><code>onDomChange(function(){ alert("The Times They Are a-Changin'"); }); </code></pre> <p>This works on IE 5.5+, FF 2+, Chrome, Safari 3+ and Opera 9.6+</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload