Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Event listener DOMNodeInserted being run multiple times, why?

I'm trying to listen for a node with a certain class being added to the DOM dynamically. Once this Node has been added i want to then add an instance of of a plugin to this Node. The problem I'm having is DOMNodeInserted is running multiple times which is then running my plugin multiple on this one Node which is causing problems.

There is only ever one occurrence of this class on page.

Why is this and how can I stop this from happening?

$(document).ready(function(){
    
    $('#editArea').live('DOMNodeInserted', '.class', function(e){

        $('.class').plugin({
            source: 'libs/ajax/somescript.php',
        });
                    
    })
    
});
like image 687
Richard Skinner Avatar asked Dec 11 '22 07:12

Richard Skinner


2 Answers

I ran into the same problem awhile back. What you need to do is debounce the function so it fires after the last DOMNodeInserted call.

Try this (adapted from John Hann's smartresize--comment/link left in):

(function ($, sr) {
        // debouncing function from John Hann
        // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
        var debounce = function (func, threshold, execAsap) {
            var timeout;
            return function debounced() {
                var obj = this, args = arguments;
                function delayed() {
                    if (!execAsap)
                        func.apply(obj, args);
                    timeout = null;
                };
                if (timeout) {clearTimeout(timeout);
                } else if (execAsap) {func.apply(obj, args);}
                timeout = setTimeout(delayed, threshold || 100);
            };
        }
        jQuery.fn[sr] = function (fn) { return fn ? this.on('DOMNodeInserted', debounce(fn)) : this.trigger(sr); };
    })(jQuery, 'debouncedDNI');

    $(document).ready(function () {
        $('#editArea').debouncedDNI(function () {
            $('.class').plugin({
                source: 'libs/ajax/somescript.php',
            });
        });
    });
like image 51
Ted Avatar answered Apr 09 '23 18:04

Ted


Probably because in your DOM whatever the element you're watching for has children elements. The event is fired once for the matching element (.class) and once for each descendant.

If your element you need to watch is something like a select with a bunch of option elements under it, a quick and dirty solution might be to watch for another "buddy" element you can put along with it in the DOM. For instance:

$(document).ready(function(){
    $('#editArea').on('DOMNodeInserted', '#classbuddy', function(e){
        $('.class').plugin({
            source: 'libs/ajax/somescript.php',
        });
    })
});

Then in your markup you would just need to add something like an empty span element with id="classbuddy". Because that span would not have children elements, your code would fire only once and so .plugin() would be applied one time only.

like image 43
hmqcnoesy Avatar answered Apr 09 '23 18:04

hmqcnoesy