outerClick event

Someone in the #mootoos irc channel wanted an event triggered only when clicked outside of an element but there's nothing built-in, so I thought that it's an interesting event to implement. And since it has at least some reusability I'm going to share the code along with a description of what it's doing.

  1. (function(){
  2. var events;
  3. var check = function(e){
  4. var target = $(e.target);
  5. var parents = target.getParents();
  6. events.each(function(item){
  7. var element = item.element;
  8. if (element != target && !parents.contains(element))
  9. item.fn.call(element, e);
  10. });
  11. };
  12. Element.Events.outerClick = {
  13. onAdd: function(fn){
  14. if(!events) {
  15. document.addEvent('click', check);
  16. events = [];
  17. }
  18. events.push({element: this, fn: fn});
  19. },
  20. onRemove: function(fn){
  21. events = events.filter(function(item){
  22. return item.element != this || item.fn != fn;
  23. }, this);
  24. if (!events.length) {
  25. document.removeEvent('click', check);
  26. events = null;
  27. }
  28. }
  29. };
  30. })();
  31.  
  32. // usage
  33. window.addEvent('domready', function(){
  34. $('test').addEvent('outerClick', function(){
  35. alert('You clicked outside of $("test").');
  36. });
  37. });
  38.  

First thing you may notice is the (function(){ /* code here */ })() pattern. That creates a private area for the events variable, which will store all the added outerClick events and the check function. This way the global namespace is not polluted.

Now let's take a look at onAdd. It checks if the events variable is set, and if not it initializes it with an empty array and adds the check function as a document click event listener. Note that this is only done once for all outerClick events added. The element and the user supplied event listener fn are pushed to the events array as the last step of onAdd.

onRemove does the same things onAdd does but in reverse. It filters the element with the function and element out of the events array and if the array is empty it removes the document click listener.

Last part of the code to discuss is the check function. The idea behind it is to check if the event target is outside the the element in events and if so it calls the event function. The target is 'inside' the element if its the element itself or if the element is one of the targets parents. In order to do the search for the parents only once per click target.getParents() is saved to a temporary variable.

The post is now way longer than expected, though I hope you've learned a bit from my first serious post.


18 Responses to outerClick event

  1. 2 Rendez 2008-06-30 09:44:48

    This is neat and extremely useful, specially for dropdowns, and popups. I always found myself programming a huge cms or extended profile page for users where there's a lot of divs and dropdowns where on clicking outside they have to be closed also.

  2. 14 Harald 2008-07-09 09:52:21

    Nice snippet and a great description, like every post.

    One suggestion: Array::filter can be replaced by Array::some.

  3. 15 kassens 2008-07-09 12:30:39

    @Harald: I think you got it wrong, the filter is there because the event should be removed from the events array. (All outerClick events are stored in the same events array.)

  4. 17 Harald 2008-07-10 07:55:05

    Ok, then what about only using the fn as index and saving the element to fn.element. When you remove the fn later on, you can read element from fn.element. Would shorten the code.

  5. 19 Jens 2008-07-18 15:40:58

    don't works with the IE7 :-( i replace window.addEvent .. with document.addEvent - and it works crossbrowser. Maybe it helps someone else.

  6. 20 kassens 2008-07-19 01:42:24

    Thanks for the report Jens, i've updated the post.

  7. 22 Dumitru 2008-07-22 17:46:03

    I have created a script that tells me if the cursor is outside the page main menu. The difference is that I used event.relatedTarget, not event.target (new Event( event ).relatedTarget). Is there a difference between them? Why do they keep them both? Is it only for the backward compatibility?

  8. 23 kassens 2008-07-23 09:33:38

    @Dumitru event.relatedTarged is the element you left (in mouseenter and mouseleave events). Have a look at the docs for more details.

  9. 24 Dumitru 2008-07-25 09:43:03

    thanks a lot for the lesson... I've been so dump not to see the difference between them both... :) That' why my script has some bugs...

    http://subasalt.ro/mercury/js/mercury.js

  10. 5431 Johan 2009-01-27 18:54:04

    Great script. Really helped me out and works flawlessly!
    Keep up the good work!

  11. 5433 Murnau 2009-05-05 22:04:08

    Great work!! Thanx!!
    That's right what I was looking for.

  12. 5434 Murnau 2009-05-05 22:05:55

    Great work!! Thanx!
    That's right that what I was looking for!

  13. 5435 Murnau 2009-05-05 22:06:40

    Great work!! Thanx!
    That's right that what I was looking for!

  14. 5436 karte 2009-07-25 16:49:08

    very valuable Information, thank you very much!

  15. 5437 tbela99 2009-07-31 16:14:36

    one question in my mind:

    what will happen if on a link I stop the event ? I guess event won't bubble till the document and then the check will not be performed.

    anyway, i'll test this.

  16. 5438 tbela99 2009-08-03 10:07:10

    outerClick is useless if we call stop() on event like in this example.

    actually, I prefer to play with things like focus/blur to achieve the same goal.

  17. 5439 tbela99 2009-08-03 10:14:18

    window.addEvent('domready', function () {

    $$('a.outerclick').addEvent('outerClick', function(){

    alert('You clicked outside of $("test").');

    });

    //outerClick is not fired on this link
    $$('a.innerclick').addEvent('click', function (e) {

    e.stop();
    });
    });

  18. 5440 Bill 2009-09-21 18:11:54

    Just added my own blog this month. I need some inspiration. Thx.

Leave a Reply



About

I'm a MooTools core developer and this is the place where I publish some snippets and other mootools related stuff. I study computer science in Darmstadt, Germany.

Idea for a Topic?

If you've got an idea for a topic to write about, let me know!

Other Blogs

User