16

I have a div that slides down when a button is clicked, and I would like to slide up the div when a user:

  1. Clicks anwhere except within the DIV itself
  2. Click a close button within the div.

Currently I've got it to a stage where, you click an element with the class .panel-tab - it slides down the panel with ID #panel... click anywhere else it slides up....

Here is my code so far to get the DIV to open and close:

<script type="text/javascript">
$(document).ready(function(){

$('.panel-tab').click(function(e) {
  $("#panel").stop(true, true).slideToggle("slow");
  e.stopPropagation();
});

$("body").click(function () {
  $("#panel:visible").stop(true, true).slideUp("slow");
});});
</script>
Reporter
  • 3,897
  • 5
  • 33
  • 47
CodeyMonkey
  • 749
  • 4
  • 8
  • 18

3 Answers3

20

You could bind a click event to the document and check if the click event happend within that div or any children. If not, close it.

Plugin time!

(function($){
    $.fn.outside = function(ename, cb){
        return this.each(function(){
            var $this = $(this),
                self = this;

            $(document).bind(ename, function tempo(e){
                if(e.target !== self && !$.contains(self, e.target)){
                    cb.apply(self, [e]);
                    if(!self.parentNode) $(document.body).unbind(ename, tempo);
                }
            });
        });
    };
}(jQuery));

usage:

$('.panel-tab').outside('click', function() {
    $('#panel').stop(true, true).slideUp('slow');
});
jAndy
  • 231,737
  • 57
  • 305
  • 359
  • Thanks for your reply, sorry, but what is the finished example using both the parts you supplied? – CodeyMonkey Jul 07 '11 at 12:06
  • @CodeyMonkey: well, you would just pull the "first part" into a `.js file`, include that on your site and use it like I did in the "second part". This works with all kind of events btw. – jAndy Jul 07 '11 at 12:09
  • @jAndy: why don't you simply always trigger the event and you stop the propagation on the element that should stay open? – meo Jul 07 '11 at 12:12
  • 1
    @meo: several reasons. I guess doing it like so is most convinient and easy to use and re-use. But for the most part, you would also have to check for any descendent node below your target. – jAndy Jul 07 '11 at 12:20
  • Thanks this does indeed work! Appreciate you taking the time. – CodeyMonkey Jul 07 '11 at 12:23
  • @meo: I have to correct myself. You're right, doing it by stopping further propagation works also. However, I'm not sure about the technique anyway. It could cause unpredictable results when there are other (delegated) events which would get blocked also. see http://jsfiddle.net/TnG4E/1/ – jAndy Jul 07 '11 at 12:35
  • very true and it works only if its the only element that sould be closed. Good point. – meo Jul 07 '11 at 12:37
  • Small note - while this plugin is brilliant and does the job, it doesn't work so well for child elements inside the element you want to allow clicks from. To remedy this, I replaced the second part of the if test, eg: `if(e.target !== ".panel-tab" && $(e.target).parents('.panel-tab').length===0)`. Now if you click on a child of `.panel-tab` it will not fire the callback. – totallyNotLizards Mar 12 '13 at 11:29
  • Something like this should be in the jQuery core. It's a very commonly used functionality. – Chris Harrison Jun 04 '13 at 04:57
  • I think i've found something that might be troublesome. You bind the event to `$(document)` and then you unbind it from `$(document.body)` if `self.parentNode` is not present. On my page it doesn't remove the listeners correctly. My fix to that problem was to remove the if-statement and change en unbinding to `$(document).unbind(ename, tempo);`. Dont we always want to remove the listener when the code has been executed to avoid multiple events firing? – Jari Thorup Palo Sep 19 '14 at 09:19
6

EDIT How to create a custom modal popup - and how to close it clicking outside of it


Here, just an example of mine: http://jsbin.com/uqiver/1/edit

$("body").on('click', function(ev) {
    var myID = ev.target.id;
    if (myID !== 'panel') {
        $('#panel').hide();
    }
});

Or you can also check if it's visible at first:

var $pan = $('#panel');

$("body").on('click', function(ev) {
    if ($pan.is(':visible') && ev.target.id !== 'panel') $pan.hide();
});

Community
  • 1
  • 1
Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
1

i would do something like this

var $doc, $panel = $('.panel-tab');
$doc = $(document);
$doc.bind("click", function(){
   $panel.hide();
   $doc.undbind("click");
});

$panel.bind("click", function(e){
   e.stopPropagation();
});

you always close the tab on the click on the document, but you stop the event from propagation on the tab it self.

here a working example: http://jsfiddle.net/meo/TnG4E/

meo
  • 30,872
  • 17
  • 87
  • 123
  • @roXon: this is mainly not working because of my typo in UNDBIND (its a problem to be German speaking ;) ). This is just an example. I'm aware that it does not gonna work in every single situations :) But if think it would do the trick for his example. – meo Jul 07 '11 at 12:50