1

I have a simple popup when you click a button. If you click the x (#close) it will close the popup. The goal is for it to also close if you click anywhere outside the popup. I have it so that if you click anything that doesn't have the class popup-content, it should close the popup. For some reason, this is not working. If I change it so it closes if you click anything that DOES have the class popup-content, then it closes when you click inside the popup.

What am I doing wrong here?

Also, is there a better way to do this that doesn't involve putting that class on every clickable part of the popup and button?

https://codepen.io/sharpdesigner/pen/wRMeeW

html

$(document).ready(function() {
  $('#trigger').click(function() {
    $('#overlay').fadeIn(300);
  });
  $('#close').click(function() {
    $('#overlay').fadeOut(300);
  });
});

$(document).mouseup(function(e) {
  $("body").click(function(e) {
    if (e.target.className !== "popup-content") {
      $('#overlay').fadeOut(300);
    }
  });
});
.pop {
  background: #000;
  color: #fff;
  text-align: center;
  font-weight: bold;
  padding: 10px 30px;
  border-radius: 3px;
  border: 1px solid #000;
  display: inline-block;
  cursor: pointer;
}

#overlay {
  position: fixed;
  height: 100%;
  width: 100%;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: rgba(0, 0, 0, 0.8);
  display: none;
}

#popup {
  max-width: 600px;
  width: 80%;
  max-height: 300px;
  height: 80%;
  padding: 20px;
  position: relative;
  background: #fff;
  margin: 20px auto;
}

#close {
  position: absolute;
  top: 10px;
  right: 10px;
  cursor: pointer;
  color: #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a id="trigger" class="pop popup-content">Click me</a>
<div id="overlay">
  <div id="popup" class="popup-content">
    <div id="close">X</div>
    <h2 class="popup-content">This is a popup</h2>
    <p class="popup-content">You just triggered a popup</p>
  </div>
</div>
Barmar
  • 741,623
  • 53
  • 500
  • 612
Andrew
  • 11
  • 1
  • 1
    I commented once without reading your full answer and deleted it, but instead of checking that the clicked element doesn't have the class `.popup-content`, you can check if it *does* have the specific ID of `#close` or `#overlay` and only hide if it has one of those IDs. https://codepen.io/anon/pen/jXGGPd –  Dec 28 '18 at 20:56
  • Reopen it, it's not the same answer as @Barmar said. I have a good one about his problem – SerCrAsH Dec 28 '18 at 21:07
  • Thank you. This works perfectly. – Andrew Dec 28 '18 at 21:08
  • To solve the question exactly as asked (even though mark.hch had a better solution), I changed if(e.target.className !== "popup-content") { to if(!$(event.target).is('.popup-content')) { – Andrew Dec 28 '18 at 21:09
  • @SerCrAsH I've reopened, but I don't see why this is any different from all the past questions about detecting clicks outside an element. – Barmar Dec 28 '18 at 21:12
  • 1
    It's almost always wrong to add one event listener inside another. Every time the `mouseup` event happens you add another `click` handler to `body`, and these cascade. – Barmar Dec 28 '18 at 21:23
  • You're not dealing with event bubbling. When you click on an element, it bubbles out to all the containing elements. Most of them do not have the `popup-content` class. – Barmar Dec 28 '18 at 21:25
  • You can also write `if (!$(event.target).hasClass("popup-content"))`. – Barmar Dec 28 '18 at 21:26

2 Answers2

1

Check this code.

There I declare the events show/hide for your popup. I added a check and a animate-on class if there is in the middle of an animation. This way you only show/hide if the animation is complete.

Finally, body is not accesible as you wanted to. The overlay tag will fullfit the page (by the css rule height/weight: 100% + position:fixed) and inside it you have your popup content. Thus, clicking everywhere would trigger the hide event; and you only want to trigger it if you clicked on #close and #overlay (last event handler: e.eventTarget.id === 'overlay') and no other place.

Codepen: https://codepen.io/anon/pen/roGGaN?editors=1111 (if you can see this, notice me) Thanks you @barmar

$(document).ready(function() {
  // Show event
 $('#overlay').on('show', function(e){
   // Check if we're in middle of an animation
   if($('#overlay').hasClass('animate-on')){
      return false;
   }
   // Show content
  $('#overlay').addClass('animate-on').fadeIn(300,
      // + Callback function
      function(e){ $(this).removeClass('animate-on')});  
  });
  // Hide event
 $('#overlay').on('hide', function(e){
   // Check if we're in middle of an animation
   if($('#overlay').hasClass('animate-on')){
      return false;
   }
   // Hide content
 $('#overlay').addClass('animate-on').fadeOut(300,
      // + Callback function
      function(e){ $(this).removeClass('animate-on')});
 });
  // Open trigger
  $('#trigger').click(function() {
    $('#overlay').trigger('show');
  });
  // Close X
  $('#close').click(function() {
    $('#overlay').trigger('hide');
  });
  
  // Outside pop-up click (just #overlay)
  $("#overlay").click(function(e) {
    if ( "overlay" === e.target.id ) {
      $('#overlay').trigger('hide');
    }
 });
});
.pop {
  background: #000;
  color: #fff;
  text-align: center;
  font-weight: bold;
  padding: 10px 30px;
  border-radius: 3px; 
  border: 1px solid #000;
  display: inline-block;
  cursor: pointer;
}

#overlay {
  position: fixed;
  height: 100%;
  width: 100%;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: rgba(0,0,0,0.8);
  display: none;
}

#popup {
  max-width: 600px;
  width: 80%;
  max-height: 300px;
  height: 80%;
  padding: 20px;
  position: relative;
  background: #fff;
  margin: 20px auto;
}

#close {
  position: absolute;
  top: 10px;
  right: 10px;
  cursor: pointer;
  color: #000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
    <a id="trigger" class="pop">Click me</a>
    <div id="overlay">
      <div id="popup" class="popup-content">
        <div id="close">X</div>
        <h2 class="popup-content">This is a popup</h2>
        <p class="popup-content">You just triggered a popup</p>
      </div>
    </div>
SerCrAsH
  • 440
  • 5
  • 14
0

If you put an trigger on the overlay. Then any click outside the popup would close it.

$(document).ready(function() {
    $('#trigger').click(function() {
        $('#overlay').fadeIn(300);  
    });
    $('#close, #overlay').click(function() {
        $('#overlay').fadeOut(300);
    });
});
Henry
  • 1,242
  • 1
  • 12
  • 10