31

Is there any way to watch, if the content within a div changes?

Let's say I have:

<div id="hello"><p>Some content here</p></div>

Which at some point 5 seconds later changes to:

<div id="hello"><ul><li>This is totally different!</li></ul></div>

How can I be notified of this via a callback or something else? I can in most cases get the javascript that's doing the inserting, to tell me. But I wanted to know if it was possible.

atp
  • 30,132
  • 47
  • 125
  • 187

6 Answers6

63

The jQuery .change() method works only for form fields.

I wrote a little jQuery plugin for you:

<!-- jQuery is required -->

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>


<!-- this is the plugin -->

<script>
  jQuery.fn.contentChange = function(callback){
    var elms = jQuery(this);
    elms.each(
      function(i){
        var elm = jQuery(this);
        elm.data("lastContents", elm.html());
        window.watchContentChange = window.watchContentChange ? window.watchContentChange : [];
        window.watchContentChange.push({"element": elm, "callback": callback});
      }
    )
    return elms;
  }
  setInterval(function(){
    if(window.watchContentChange){
      for( i in window.watchContentChange){
        if(window.watchContentChange[i].element.data("lastContents") != window.watchContentChange[i].element.html()){
          window.watchContentChange[i].callback.apply(window.watchContentChange[i].element);
          window.watchContentChange[i].element.data("lastContents", window.watchContentChange[i].element.html())
        };
      }
    }
  },500);
</script>



<!-- some divs to test it with -->

<p>Testing it:  (click on divs to change contents)</p>

<div id="a" onclick="$(this).append('i')">Hi</div>
<div id="b" onclick="$(this).append('o')">Ho</div>
<div class="c" onclick="$(this).append('y')">He</div>
<div class="c" onclick="$(this).append('w')">He</div>
<div class="c" onclick="$(this).append('a')">He</div>




<!-- this is how to actually use it -->

<script>
  function showChange(){
    var element = $(this);
    alert("it was '"+element.data("lastContents")+"' and now its '"+element.html()+"'");
  }

  $('#a').contentChange(function(){  alert("Hi!") });
  $('div#b').contentChange( showChange );
  $('.c').contentChange(function(){  alert("He he he...") });
</script>

Be aware that this watches changes in the contents of the element (html) only, not the attributes.

Sebastián Grignoli
  • 32,444
  • 17
  • 71
  • 86
  • 2
    Thanks. Clearly the only way to do it is to manually set a timer. I probably will never need to use the plugin, but kudos for writing it. – atp Jul 13 '10 at 14:12
  • Be aware that this watches changes in the contents of the element (html) only, not the attributes. – Sebastián Grignoli Jul 15 '10 at 03:39
  • 1
    It uses setInterval = 500 ms. It will flash, users can see changes. I need immediately do job when content changes. Also i cant use setInterval = 1 ms - it will eat the processor of computer – Vova Popov Dec 28 '12 at 21:24
  • If you have access to the function that makes the change (let's say it's called `changethings()`) you could extend it like this: (in pseudocode) `var funcThatChangesThings = changethings; changethings = function(...args...){ funcThatChangesThings(...args...); notifyChanges(); }` assuming that notifyChanges() is your callback. The new function should have the same signature (arguments) than the real function. – Sebastián Grignoli Feb 26 '14 at 20:32
8

There is no native jQuery/DOM event that will fire when HTML/DOM content changes.

You could (if you are feeling particularly wasteful) do something like this:

$(function() {
  var $div = $("#hello");
  var html = $div.html();
  var checking = setInterval(function() {
    var newhtml = $div.html();
    if (html != newhtml) {
      myCallback();
      html = newhtml;
    }
  },100);

  function myCallback() {
    alert('content changed!');
    // if you only want it to fire once, uncomment the following:
    // clearInterval(checking);
  }
});

Just remember, calling .html() every 100ms is probably not the best idea for your sites performance.

jsFiddle mockup

gnarf
  • 105,192
  • 25
  • 127
  • 161
  • 1
    Actually, there is. The implementation of these so-called [mutation events](https://developer.mozilla.org/en/XUL/Events#Mutation_DOM_events) is [slow](http://groups.google.com/group/mozilla.dev.platform/browse_thread/thread/2f42f1d75bb906fb?pli=1), though. – Rob W Jan 19 '12 at 09:37
2

Maybe, it's reasonable to monitor the source of events that amend the contents of your layer(s)? Say, a user has clicked anywhere (read, "did a click") after what the contents may had changed. So if you check the .html() after a click rather than using a loop - it might save some system resources.

Nixter
  • 51
  • 4
1

Who/what will change this? If it's some JS you control, use that to also trigger your callback. Obviously a user cannot change this.

If you want to watch a <input> element etc, use the 'change' event. jQuery version here: http://api.jquery.com/change/

psychotik
  • 38,153
  • 34
  • 100
  • 135
0

Here's a code sample that calls a simple alert when the given value changes:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>watchu, watchu, watchu want, watchu want?</title>
</head>
<body>

    <div id='foo'>Hello World!</div>

    <p><input type="button" id="ChangeButton" value="Change It" /></p>

    <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
    <script type="text/javascript">

        $(function () {

            $('#ChangeButton').click(function () {
                $('#foo').html('Awfveeterzain!');
            });

            window.watchForChangeOriginalValue = $('#foo').html();
            watchForChange();
        });

        function watchForChange() {
            if ($('#foo').html() != window.watchForChangeOriginalValue)
                alert('the value changed!');
            else
                window.setTimeout(watchForChange, 500);
        }

    </script>
</body>
</html>
a7drew
  • 7,801
  • 6
  • 38
  • 39
0

There are some events called DOMNodeInserted, DOMNodeRemoved and DOMSubtreeModified. Which check is there any elements are added or removed or any inner Html changed inside a div. for this you need an setInterval() function.

 function DivChange() {      
    $('#YourDiv').bind('DOMNodeInserted DOMNodeRemoved', function (event) {
        if (event.type == 'DOMNodeInserted') {
            alert('Content added');
        } else if (event.type == 'DOMNodeRemoved')  {
            alert('Content removed');
        } else {
            alert('Inner Html changed for some content');
        }
    });
}
var DivTimer = setInterval(DivChange, 1000);

The above functions will checks the Div for any content change, for every second

Note: This events are not supported by IE

Prem
  • 630
  • 2
  • 11
  • 25