Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I call a function every time the DOM changes in jQuery?

I need to ensure that a page stays the way my script describes even after the DOM changes; my script has to handle these changes to the DOM such that my script doesn't only handle on the initial state.

Is there an event that I can use to handle these DOM changes?

like image 636
Tamara Wijsman Avatar asked Dec 03 '11 16:12

Tamara Wijsman


1 Answers

Taking your question in the strictest sense, something like this:

//--- Narrow the container down AMAP.
$("YOUR SELECTOR").bind ("DOMSubtreeModified", HandleDOM_ChangeWithDelay);

var zGbl_DOM_ChangeTimer = null;

function HandleDOM_ChangeWithDelay (zEvent) {
    if (typeof zGbl_DOM_ChangeTimer == "number") {
        clearTimeout (zGbl_DOM_ChangeTimer);
        zGbl_DOM_ChangeTimer = '';
    }
    zGbl_DOM_ChangeTimer     = setTimeout (HandleDOM_Change, 333);
}

function HandleDOM_Change () {
    // YOUR CODE HERE.
}

Note that you want the intermediate delay function because the changes will come in clusters of 10 to 100's of events on a site like Youtube or Google.

You only want to fire on the last event of a cluster -- that's when the change you care about is finished.



IMPORTANT:

It's been a while since I've used the DOMSubtreeModified approach, because it performs poorly in practice. So, I forgot I had a utility function for it.

Also, as Raynos reminds, mutation events are deprecated. So, Firefox may stop supporting these events in some future release.

One other problem: If your script also changes the nodes in the container you are monitoring, the script can get stuck in an infinite loop/recursion.

Here is the code to avoid the loop (and that global variable):

function HandleDOM_Change () {
    // YOUR CODE HERE.
}

//--- Narrow the container down AMAP.
fireOnDomChange ('YOUR JQUERY SELECTOR', HandleDOM_Change, 100);

function fireOnDomChange (selector, actionFunction, delay)
{
    $(selector).bind ('DOMSubtreeModified', fireOnDelay);

    function fireOnDelay () {
        if (typeof this.Timer == "number") {
            clearTimeout (this.Timer);
        }
        this.Timer  = setTimeout (  function() { fireActionFunction (); },
                                    delay ? delay : 333
                                 );
    }

    function fireActionFunction () {
        $(selector).unbind ('DOMSubtreeModified', fireOnDelay);
        actionFunction ();
        $(selector).bind ('DOMSubtreeModified', fireOnDelay);
    }
}
like image 102
Brock Adams Avatar answered Nov 04 '22 23:11

Brock Adams