37

I have an ajax callback which injects html markup into a footer div.

What I can't figure out is how to create a way to monitor the div for when it's contents change. Placing the layout logic I'm trying to create in the callback isn't an option as each method (callback and my layout div handler) shouldn't know about the other.

Ideally I'd like to see some kind of event handler akin to $('#myDiv').ContentsChanged(function() {...}) or $('#myDiv').TriggerWhenContentExists( function() {...})

I found a plugin called watch and an improved version of that plugin but could never get either to trigger. I tried "watching" everything I could think of (i.e. height property of the div being changed via the ajax injection) but couldn't get them to do anything at all.

Any thoughts/help?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
jas
  • 539
  • 1
  • 5
  • 10
  • What method are you using to inject the content? – outis Dec 26 '09 at 09:14
  • in this case I'm using the jQuery Layout plugin. In the west pane I have a content div and footer div. The layout is initialized before the ajax call so the content panel of the pane takes up 100% of the pane height. My success callback, if more rows than room exist, knows to create a paginate pager into the footer div via it's id... var success = function(data) { $(divid).paginate(options);... }. But it doesn't know it's in a layout object. I need to trigger layout.resizeContent("west"); somehow but don't want to hardwire jQuery UI Layout logic in the callback. – jas Dec 29 '09 at 05:18

5 Answers5

52

The most effective way I've found is to bind to the DOMSubtreeModified event. It works well with both jQuery's $.html() and via standard JavaScript's innerHTML property.

$('#content').bind('DOMSubtreeModified', function(e) {
  if (e.target.innerHTML.length > 0) {
    // Content change handler
  }
});

http://jsfiddle.net/hnCxK/

When called from jQuery's $.html(), I found the event fires twice: once to clear existing contents and once to set it. A quick .length-check will work in simple implementations.

It's also important to note that the event will always fire when set to an HTML string (ie '<p>Hello, world</p>'). And that the event will only fire when changed for plain-text strings.

Courtney Christensen
  • 9,165
  • 5
  • 47
  • 56
  • 4
    It's probably worth noting that `DOMSubtreeModified` is technically deprecated. It looks like DOM4 will provide a viable alternative, someday. See: http://stackoverflow.com/questions/6659662/why-is-the-domsubtreemodified-event-deprecated-in-dom-level-3 – Courtney Christensen Mar 30 '12 at 15:33
7

You can listen for changes to DOM elements (your div for example) by binding onto DOMCharacterDataModified tested in chrome but doesn't work in IE see a demo here
Clicking the button causes a change in the div which is being watched, which in turn fills out another div to show you its working...


Having a bit more of a look Shiki's answer to jquery listen to changes within a div and act accordingly looks like it should do what you want:

$('#idOfDiv').bind('contentchanged', function() {
    // do something after the div content has changed
    alert('woo');
});

In your function that updates the div:

$('#idOfDiv').trigger('contentchanged');

See this as a working demo here

Community
  • 1
  • 1
Scoobler
  • 9,696
  • 4
  • 36
  • 51
5

There is a neat javascript library, mutation-summary by google, that lets you observe dom changes concisely. The great thing about it, is that if you want, you can be informed only of the actions that actually made a difference in the DOM, to understand what I mean you should watch the very informative video on the project's homepage.

link: http://code.google.com/p/mutation-summary/

jquery wrapper: https://github.com/joelpurra/jquery-mutation-summary

Ricardo Freitas
  • 533
  • 1
  • 6
  • 9
3

You might want to look into the DOMNodeInserted event for Firefox/Opera/Safari and the onpropertychange event for IE. It probably wouldn't be too hard to utilize these events but it might be a little hack-ish. Here is some javascript event documentation: http://help.dottoro.com/larrqqck.php

ornerylawn
  • 524
  • 1
  • 4
  • 9
0

Now we can use a MutationObserver ; Well, apparently we must.

Use of Mutation Events is deprecated. Use MutationObserver instead. jquery.min.js:2:41540

From https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver :

// Select the node that will be observed for mutations
const targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
const config = { attributes: true, childList: true, subtree: true };

// Callback function to execute when mutations are observed
const callback = function(mutationsList, observer) {
    // Use traditional 'for loops' for IE 11
    for(const mutation of mutationsList) {
        if (mutation.type === 'childList') {
            console.log('A child node has been added or removed.');
        }
        else if (mutation.type === 'attributes') {
            console.log('The ' + mutation.attributeName + ' attribute was modified.');
        }
    }
};

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

// Later, you can stop observing
observer.disconnect();
yPhil
  • 8,049
  • 4
  • 57
  • 83