0

I know I can attach an custom event like this

$("#customDropdownBox").on("clickOutside", function(){
    $(this).hide(300, hideCallback);
})

I know I can attach a click event on the body to find every elements which has the custom event attached to them like this

$("body").on("click", function(event){
    $.each($("body *"), function(i, o){
        if($._data(o, "events") && $._data(o, "events")["clickOutside"])
            $(o).trigger("clickOutside");
    })
})

I was wondering if there could be a faster way of doing this without having to loop through ALL (*) elements of the DOM. I know I can filter by using something like

$("body div.classx")

but I'd rather not hardcode a specific ID or class. I was wondering if there was a kind of selector that could acheive this. Something like

$("body *{event:'clickOutside'}")

or

$.findEvent("clickOutside");
Guillaume Bois
  • 1,302
  • 3
  • 15
  • 23
  • possible duplicate of [jQuery find events handlers registered with an object](http://stackoverflow.com/questions/2518421/jquery-find-events-handlers-registered-with-an-object) – Paul Fleming Dec 21 '12 at 19:13
  • 3
    That is not a duplicate, this question doesn't ask how to get the events that are bound on an element. – Kevin B Dec 21 '12 at 19:15
  • There is no built-in way to do this, however you could monkeypatch the event binding methods and the cleanData method to store an internal array of elements that have events, then you could just loop through those elements rather than all elements. – Kevin B Dec 21 '12 at 19:18
  • If you are just trying to capture a click outside event for your custom dropdown, here are some other options to consider http://stackoverflow.com/questions/152975/how-to-detect-a-click-outside-an-element – MichaC Dec 21 '12 at 19:29
  • You could use `filter()`, but it will create a loop as well. Why not just add a class or a data-attribute? – Johan Dec 21 '12 at 20:55

1 Answers1

0

+1 for @Kevin B. I learned new words today "monkey patch" and "duck punching" :). That's what i did. Here is the code. The monkey patching of "on" and "off" methods as explained in details here and in a loop here

// Monkey patch on and off methods
(function($, window){
    window.clickOutside = [];
    var _oldOn = $.fn.on;
    $.fn.on = function(event,handler){
        if(event == "clickOutside"){
            $.fn.off.apply(this, arguments); // make sure the event is never registered twice
            window.clickOutside.push(this[0]);
        }
        return _oldOn.apply(this, arguments);
    };
    var _oldOff = $.fn.off;
    $.fn.off = function(event,handler){
        if(event == "clickOutside"){
            $.each(window.clickOutside, function(i, o){
                if(this == o){
                    window.clickOutside.splice(i, 1);
                }
            })
        }
        return _oldOff.apply(this, arguments);
    };
})(jQuery, window);

and now my listen function is now as follows

// Listen for clickOutside/clickElseWhere events
$("body").on("click", function(event){
    var $target = $(event.target);
    $.each(window.clickOutside, function(i, o){
        if($._data(o, "events") && $._data(o, "events")["clickOutside"] && !$(o).find("*").andSelf().has($target).length){
            $(o).trigger("clickOutside");
        }
    });
});

Which let me loop on only the elements that have that specific event.

Guillaume Bois
  • 1,302
  • 3
  • 15
  • 23