Create a jQuery special event for content changed

18,386

Solution 1

also take a look to James similar script (declaring as jquery object method and not as event)

jQuery.fn.watch = function( id, fn ) {

    return this.each(function(){

        var self = this;

        var oldVal = self[id];
        $(self).data(
            'watch_timer',
            setInterval(function(){
                if (self[id] !== oldVal) {
                    fn.call(self, id, oldVal, self[id]);
                    oldVal = self[id];
                }
            }, 100)
        );

    });

    return self;
};

jQuery.fn.unwatch = function( id ) {

    return this.each(function(){
        clearInterval( $(this).data('watch_timer') );
    });

};

and creating special event

jQuery.fn.valuechange = function(fn) {
    return this.bind('valuechange', fn);
};

jQuery.event.special.valuechange = {

    setup: function() {

        jQuery(this).watch('value', function(){
            jQuery.event.handle.call(this, {type:'valuechange'});
        });

    },

    teardown: function() {
        jQuery(this).unwatch('value');
    }

};

Anyway, if you need it only as event, you script is nice :)

Solution 2


I know this post/question is a little old, but these days I was behind a similar solution and I found this:

$('#selector').bind('DOMNodeInserted', function(e) {
    console.log(e.target);
});

Source: http://naspinski.net/post/Monitoring-a-DOM-Element-for-Modification-with-jQuery.aspx

Hope this help someone!

Solution 3

The finished code in the original question worked for me, thank you! I would just like to note that I am using jquery 1.9.1 and $.event.handle seems to have been removed. I changed the following to get it to work.

jQuery.event.handle.call(self, {type:'contentchange'});

to

jQuery.event.dispatch.call(self, {type:'contentchange'});

Share:
18,386
Sindre Sorhus
Author by

Sindre Sorhus

Updated on June 05, 2022

Comments

  • Sindre Sorhus
    Sindre Sorhus about 2 years

    I'm trying to create a jQuery special event that triggers when the content that is bound, changes. My method is checking the content with a setInterval and check if the content has changed from last time. If you have any better method of doing that, let me know. Another problem is that I can't seem to clear the interval. Anyway, what I need is the best way to check for content changes with the event.special.

    (function(){
    
        var interval;
        
        jQuery.event.special.contentchange = {
            setup: function(data, namespaces) {
                var $this = $(this);
                var $originalContent = $this.text();
                interval = setInterval(function(){
                    if($originalContent != $this.text()) {
                        console.log('content changed');
                        $originalContent = $this.text();
                        jQuery.event.special.contentchange.handler();
                    }
                },500);
            },
            teardown: function(namespaces){
                clearInterval(interval);
            },
            handler: function(namespaces) {
                jQuery.event.handle.apply(this, arguments)
            }
        };
        
    })();
    

    And bind it like this:

    $('#container').bind('contentchange', function() {
            console.log('contentchange triggered');
    });
    

    I get the console.log 'content changed', but not the console.log 'contentchange triggered'. So it's obvious that the callback is never triggered.

    I just use Firebug to change the content and to trigger the event, to test it out.

    Update
    I don't think I made this clear enough, my code doesn't actually work. I'm looking for what I'm doing wrong.


    Here is the finished code for anyone interested

    (function(){
        
        var interval;
            
        jQuery.event.special.contentchange = {
            setup: function(){
                var self = this,
                $this = $(this),
                $originalContent = $this.text();
                interval = setInterval(function(){
                    if($originalContent != $this.text()) {
                        $originalContent = $this.text();
                        jQuery.event.handle.call(self, {type:'contentchange'});
                    }
                },100);
            },
            teardown: function(){
                clearInterval(interval);
            }
        };
            
    })();
    

    Thanks to Mushex for helping me out.

    • meder omuraliev
      meder omuraliev almost 15 years
      Any reason you're not using 'var' for $this declaration?
    • meder omuraliev
      meder omuraliev almost 15 years
      And do you have consistent spelling of 'orginalContent' in the real page?
    • David Andres
      David Andres almost 15 years
      when is teardown called?
    • Sindre Sorhus
      Sindre Sorhus almost 15 years
      @David Andres - when I unbind the event. $('#container').unbind('contentchange');
    • Asaf
      Asaf almost 13 years
      If I'm not mistaken this implementation will only keep the last timer id. to fix it I would do something like $(this).data("onchange.timer.id",interval) and retrieve in the teardown
    • vsync
      vsync over 7 years
      Your "finished" code logic has a major BUG since each time .on("contentchange".. is binded, it will override the general interval variable, which would hinder other contentchange event which might have been binded previously... been 8 years, you can fix it to work better :)
  • Sindre Sorhus
    Sindre Sorhus almost 15 years
    What I'm looking for is how to just create a special event, like I have done, only one that actualy works. Can you show me that?
  • Mushex Antaranian
    Mushex Antaranian almost 15 years
    I thought you solved it and just bring this example to you to see a little different approach to this problem. If your script actually doesn't work yet, let me know.
  • Sindre Sorhus
    Sindre Sorhus almost 15 years
    My script doesn't work. Would be great if you could help me make it work :) And by the way, thanks for the other approach.
  • Sindre Sorhus
    Sindre Sorhus almost 15 years
    Thanks :) Good to know that I was close.
  • mkoistinen
    mkoistinen over 11 years
    Hardly worth a downvote. Many things are deprecated, but until ALL browsers offer a better solution, they'll still be used, and it is still useful to understand. (+1 offset vote here)
  • TCHdvlp
    TCHdvlp over 9 years
    neat ! A lot cleaner that a timer even if it's deprecated !
  • Michael Scheper
    Michael Scheper almost 9 years
    Deprecated, yes, but there's a CSS3 replacement. stackoverflow.com/a/25256569/1450294 Even IE finally supports it (in version 11)! caniuse.com/#feat=mutationobserver