DOMNodeInserted equivalent in IE?
No, there isn't. The nearest is the propertychange
event, which fires in response to a change in an attribute or CSS property of an element. It fires in response to changing the innerHTML
property of an element directly but not when the contents of the elements are altered by some other means (e.g. by using DOM methods such as appendChild()
or by altering the innerHTML
of a child element).
UPDATE 6 February 2014
As pointed out in the comments, there is a workaround. It's based on an elaborate hack and I'd recommend using mutation observers instead wherever possible.Alternative to DOMNodeInserted
If you are creating a web app that targets recent mobile phones and newer versions of browsers (Firefox 5+, Chrome 4+, Safari 4+, iOS Safari 3+, Android 2.1+), you can use the following code to create an awesome event for the insertion of dom nodes, and it even runs on the nodes initially part of the page's static mark-up!
Here's the link to the full post with and example: http://www.backalleycoder.com/2012/04/25/i-want-a-damnodeinserted/
Note on Mutation Observers: while the newer Mutation Observers features in recent browsers are great for monitoring simple insertions and changes to the DOM, do understand that this method can be used to do far more as it allows you to monitor for any CSS rule match you can thing of. This is super powerful for many use-cases, so I wrapped this up in a library here: https://github.com/csuwildcat/SelectorListener
You'll need to add the appropriate prefixes to the CSS and animationstart event name if you want to target various browsers. You can read more about that in the post linked to above.
The basic node insertion case
CSS:
@keyframes nodeInserted {
from {
outline-color: #fff;
}
to {
outline-color: #000;
}
}
div.some-control {
animation-duration: 0.01s;
animation-name: nodeInserted;
}
JavaScript:document.addEventListener('animationstart', function(event){
if (event.animationName == 'nodeInserted'){
// Do something here
}
}, true);
Listening for more complex selector matches:
This enables things that are almost impossible to do with Mutation Observers
CSS:
@keyframes adjacentFocusSequence {
from {
outline-color: #fff;
}
to {
outline-color: #000;
}
}
.one + .two + .three:focus {
animation-duration: 0.01s;
animation-name: adjacentFocusSequence;
}
JavaScript:document.addEventListener('animationstart', function(event){
if (event.animationName == 'adjacentFocusSequence'){
// Do something here when '.one + .two + .three' are
// adjacent siblings AND node '.three' is focused
}
}, true);
What Event should I register on DOM Update with Internet Explorer
I've figured it out after reading some of the source of head.js. This calls for a bit of creative javascript magic.
The events we're interested in are onreadystatechange, and onload. You can attach a custom function to these to trigger update notifications when they insert into the page.
I've abstracted this into a function, where, if you pass it an element and a callback statement, it'll dump the element at the end of the page body and run the callback.
function loadElement(e, callback) {
if ( typeof(callback) === 'function' ) {
e.onreadystatechange = e.onload = function() {
var state = e.readyState;
if ( !callback.done && (!state || /loaded|complete/.test(state)) ) {
callback.done = true;
callback();
}
}
}
document.body.appendChild(e);
}
Though I've posted this answer to my problem, I'm interested in alternative approaches to this :). How to call a function in every element in the DOM even if they are dynamically created
You were close. Try:
$(document).on("load", ".red", function(){ this.css({backgroundColor: "pink"}) });
Oops, that doesn't work. This does http://jsfiddle.net/4Bv9r/$('body').on('DOMNodeInserted', ".red", function(){ $(this).css({backgroundColor: "pink"}) });
Preferred way of modifying elements that have yet to be created (besides events)
In my opinion, the DOM Level 3 events DOMNodeInserted
help (which fires only for nodes) and DOMSubtreeModified
help (which fires for virtually any modification, like attribute changes) are your best shot to accomplish that task.
Of course, the big downside of those events is, that the Internet Explorers of this world don't support them
(...well, IE9 does).
The other reasonable solution for this problem, is to hook into any method Which can modify the DOM. But then we have to ask, what is our scope here?
Is it just enough to deal with DOM modification methods from a specific library like jQuery? What if for some reason another library is modifying the DOM or even a native method ?
If it's just for jQuery, we don't need .sub()
at all. We could write hooks in the form of:
HTML
<div id="test">Test DIV</div>
JS(function(_append, _appendTo, _after, _insertAfter, _before, _insertBefore) {
$.fn.append = function() {
this.trigger({
type: 'DOMChanged',
newnode: arguments[0]
});
return _append.apply(this, arguments);
};
$.fn.appendTo = function() {
this.trigger({
type: 'DOMChanged',
newnode: this
});
return _appendTo.apply(this, arguments);
};
$.fn.after = function() {
this.trigger({
type: 'DOMChanged',
newnode: arguments[0]
});
return _after.apply(this, arguments);
};
// and so forth
}($.fn.append, $.fn.appendTo, $.fn.after, $.fn.insertAfter, $.fn.before, $.fn.insertBefore));
$('#test').bind('DOMChanged', function(e) {
console.log('New node: ', e.newnode);
});
$('#test').after('<span>new span</span>');
$('#test').append('<p>new paragraph</p>');
$('<div>new div</div>').appendTo($('#test'));
A live example of the above code can be found here: http://www.jsfiddle.net/RRfTZ/1/
This of course requires a complete list of DOMmanip methods. I'm not sure if you can overwrite native methods like .appendChild()
with this approach. .appendChild
is located in Element.prototype.appendChild
for instance, might be worth a try.
update
I tested overwriting Element.prototype.appendChild
etc. in Chrome, Safari and Firefox (official latest release). Works in Chrome and Safari but not in Firefox!
There might be other ways to tackle the requirement. But I can't think of a single approach which is really satisfying, like counting / watching all descendents of a node (which would need an
interval
or timeouts
, eeek).Conclusion
A mixture of DOM Level 3 events where supported and hooked DOMmanip methods is probably the best you can do here.
DOMNodeInserted/Removed event polyfills (or similar events)
I ended up writing a reasonably compliant polyfill for MutationObserver
using interval checks of a cloned childList
(similar to what @plalx mentioned in his comments) instead of falling back on the MutationEvent
s. MutationEvent
s will be more performant for most scenarios as any poll vs interrupt implementations but compatibility sucks
Simple auto scrolling example using my shim
Related Topics
JavaScript Loop Variable Scope
How to Stop Intense JavaScript Loop from Freezing the Browser
Why Do I Need to Copy an Array to Use a Method on It
Unexpected Token Illegal in Webkit
How to Detect If JavaScript Files Are Loaded
How Is a JavaScript Hash Map Implemented
How to Disable the Back Button in the Browser Using JavaScript
JavaScript - Generating All Combinations of Elements in a Single Array (In Pairs)
Get the Current Year in JavaScript
JavaScript Request Fullscreen Is Unreliable
How to Get the Hue of a #Xxxxxx Colour
How to Check If an Embedded Svg Document Is Loaded in an HTML Page
JavaScript Replace() Method Dollar Signs
Authorization of Google Drive Using JavaScript
How to Export Socket.Io into Other Modules in Nodejs
JavaScript Es6 Typeerror: Class Constructor Client Cannot Be Invoked Without 'New'