views:

344

answers:

3

Is there any event in Internet Explorer, that is fired whenever DOM is changed? For example:

document.attachEvent("ondocumentchange", function () {
    alert("you've just changed DOM!");
});

And when I execute:

document.appendChild(document.createElement("img"));

Window with text "you've just changed DOM!" appears.

I try to emulate "advanced" CSS selectors (e.g. +, >, [attr]) in IE6 using Javascript. However to work properly with dynamic content, they would have to be recalculated after each change in document.

+1  A: 

You want to look at dom mutation events - see http://en.wikipedia.org/wiki/DOM_Events, and scroll down to the section on mutation events. Only problem is that support for these events is pretty sketchy, so be careful using them. Notably, a lack of support at all in IE or Opera. Firefox, Safari and Chrome seem to be the only ones.

Something like:

document.addEventListener("DOMSubtreeModified", function () {
    alert("you've just changed DOM!");
});

According to http://www.quirksmode.org/dom/events/index.html for these kind of events you need to use addEventListener, not attachEvent. The event apparently bubbles, so that should be fine.

Kazar
"[…] lack of support at all in IE […]" – that's the problem – I need this event because of IE.
Jakub Kulhan
Afraid I don't think there is a way of doing it then, at least not without recursing over the DOM tree manually. Can you not narrow down the changes to a specific child node?
Kazar
A: 

Off the top of my head, this might work:

document.body.attachEvent('onpropertychange', function(event) {
  if (event.propertyName !== 'innerHTML') return;
  alert("you've just changed DOM!");
});

This relies on IE's proprietary onPropertyChange event — since the document's innerHTML would change whenever a node is inserted. But:

  1. It might not work with certain types of properties. I imagine innerHTML would function like a "getter" in that it'd only get recalculated when retrieved.

  2. It would also pick up a lot of false positives — lots of other things would modify the innerHTML that would have nothing to do with node insertion. You could mitigate this by listening on a particular element, rather than document-wide.

savetheclocktower
Unfortunately, "Changing the `innerText` or `innerHTML` of child elements will not cause the __onpropertychange__ event to fire for the parent element," says the documentation. And even when function is attached to every DOM element, it is not called if I use DOM manipulation functions – only if innerHTML is changed directly.
Jakub Kulhan
+1  A: 

Brute-force "solution":

(function (previousInnerHTML) {
    return function () {
        if (document.body.innerHTML !== previousInnerHTML) {
            alert("you've just (at max 33ms ago) changed DOM");
        }
        setTimout(arguments.callee, 33);
    };
})(document.body.innerHTML)();
Jakub Kulhan
Ugly, but works in IE6.
Jakub Kulhan