jQuery - run a function when DOM changes
I've been using livequery so far which works, but it makes the page browsing seem really slow. So I'm trying to find a alternative solution for this.
I'm attaching a function that runs some ajax on elements with a certain class, like:
$(".blah").each(function(){
$.ajax({
...
success: function(data) {
$(this).removeClass(".blah");
// do other stuff
}
});
});
Now I have several events hooked on different elements that can append html in the DOM, like:
$(".button").click(function(){
$.ajax({
...
success: function(data) {
$(this).append(data);
// here, new elements with ".blah" class could be inserted in the DOM
// the event above won't be fire开发者_C百科d...
}
});
});
How could I make so the first ajax function above runs when the DOM gets updated in the other events?
Update:
I also found this plugin: http://www.thunderguy.com/semicolon/2007/08/14/elementready-jquery-plugin/
Do you think it would be a better solution? From a quick look it seems to, because it allows you to set a "polling" interval, which might decrease cpu usage if you set it to 1 sec or somehting. I'm testing it now :)
Update 2:
Unfortunately it only works with element IDs for some weird reason :(
Most major browsers (but sadly not IE <= 8) support DOM mutation events (also see MDN). If you're interested in just nodes being added to the DOM, use the DOMNodeInserted
event. If you want to be informed about any DOM change, use the catch-all DOMSubtreeModified
event.
For example:
document.addEventListener("DOMNodeInserted", function(evt) {
alert("Node inserted. Parent of inserted node: " + evt.relatedNode.nodeName);
}, false);
document.body.appendChild( document.createElement("div") );
Update 13 December 2012
DOM mutation events are now deprecated and browsers are gradually moving to mutation observers. The most sensible strategy at the moment seems to be to use mutation observers and fall back to mutation events.
It's true because the new elements do not have events bound to callbacks, they are just new fresh elements. I would recommend to bind events on the newly created elements just after they are created (i.e. inside the ajax success function):
$(".blah").each(function(){
$.ajax({
...
success: function(data) {
$(this).removeClass(".blah");
// add handlers to new elements with class "button"
$(this).find('.button').click(function() {
$.ajax({
success: function(data) {
$(this).append(data);
});
}
});
}
I have encountered a problem like this as well. There is no true way to have something run on dom change (that I know of). I have approached this via two different methods
- Have a setTimeout calling the function every second or have the function triggered when the user moves the mouse. Both of these can caused slow downs if not handled correctly
- Have a function called when the ajax is done. So just have doAjax() called every time you complete a query by having it in the success section.
You could also have the first ajax query bound the body tag, so anytime the user clicks something the ajax event would fire, and then check if the right criteria is met.
Edit: This might work. Add $("BODY ID/CLASS").change(function () {}); Not totally sure, as I am not the most fluent in jQuery.
IE9+, FF and Chrome :
var observeDOM = (function(){
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
eventListenerSupported = window.addEventListener;
return function(obj, callback){
if( MutationObserver ){
// define a new observer
var obs = new MutationObserver(function(mutations, observer){
if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
callback();
});
// have the observer observe foo for changes in children
obs.observe( obj, { childList:true, subtree:true });
}
else if( eventListenerSupported ){
obj.addEventListener('DOMNodeInserted', callback, false);
obj.addEventListener('DOMNodeRemoved', callback, false);
}
}
})();
observeDOM( $('#dom_element')[0] ,function(){
console.log('dom changed');
});
精彩评论