I need to trigger an action when content is added to a Web page. The updates can be of different nature (AJAX, delayed scripts, user action for example) and are not under my control.
I wanted to use DOM mutation events, but they are not available in all browsers. Are there cross-browser libraries for this, that offer a fallback plan?
Also, I'd be interested to know if Internet Explorer 9 will support these DOM mutation events.
Thanks!
There are two ways to do this...
One, you can take a snapshot of the dom (var snap = document.body
), compare that to the dom 100ms later and then reset snap
to the body again. I'll let you be creative on how to compare them: iteration seems to be the common answer. It's not pretty.
The other option is to have a special function in any functions you create that add/remove elements in your application. This function would iterate through just the elements you add (or destroy) and look for a match.
/* Shim matchesSelector */
if (!Element.prototype.matchesSelector) {
Element.prototype.matchesSelector =
Element.prototype.matches ||
Element.prototype.webkitMatchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector;
}
function addingToDom(elm){
/* Whichever method you want to use to map selectors to functions */
var callbacks = array(['.class', fn-reference1], ['#id', fn-reference2], ['div', fn-reference3]);
/* go through all the elements you're adding */
for (var i = 0; i<elm.length; ++i){
/* go through all the selectors you're matching against */
for (var k = 0; k<callbacks.length ++k){
if(elm[i].matchesSelector(callbacks[k][0])){
/* call function with element passed as parameter */
callbacks[k][1](elm[i]);
}
}
}
}
That may not be perfect, but it should give you an idea of where to head. Call this function (addingToDom) passing the elements you just added as the argument. Create a similar function for deleting elements (or same function, but condition a separate array of callbacks).
This is an extrapolation of a current (large and messy) code I'm using to test out some ideas. I've tested matches selector as far back as ie7 with this shim, and it seems to work great!
I've considered, but not looked in to, the possibility of the element having some sort of parameter that could be set as a function that gets called when it's added, passing itself as a parameter. BUT, that's probably far-fetched.
You can easily trigger an action by setting a function and using JSONP for AJAX requests to call that function. The same function can be called during a user action.
Well... here's an idea to tell if an element has been added: append a class to each element on the page, then use query to find each element that doesn't have that class querySelectorAll(':not(.myclass)')
, then loop through those.
You'd still have to run it on an interval, but querySelectorAll is quick as it's native browser, and if it returns 'empty' (false
? null
? don't know off the top of my head) you don't do anything, and it should be minimal overhead that way.
I just came across an interesting hack that relies on css events:
http://www.backalleycoder.com/2012/04/25/i-want-a-damnodeinserted/
According to the author this works in IE10, Firefox 5+, Chrome 3+, Opera 12, Android 2.0+, Safari 4+, and nearly every version if iPhone Safari.