Beppe
Beppe

Reputation: 207

Close overlay by clicking on background

I'm trying to close an overlay window by clicking on the outer body only. The problem is that the overlay get closed even if I click on the overlay panel itself and if I click on any other element i put in it (divs, buttons, icons etc etc...) I don't know how to target only the body around the overlay and not the overlay window itself. Can you please help?

Here is both html markup and related JS.

<div id="main">
    <div class"other-content">
        <!-- other content -->
    </div>
    <!-- The Modal -->
    <div id="myModal" class="modal">
        <!-- Modal content -->
        <div class="modal__content">
            <!-- some content - divs, buttons etc etc -->
        </div>
    </div>
</div>
       $(document).on('click',"#myModal", function(e) {       
          $('#myModal').fadeOut();                
       });

Upvotes: 1

Views: 17735

Answers (5)

trungvose
trungvose

Reputation: 20034

As my understanding you are styling:

  • .modal with 100% width and height, position fixed. It also has opacity background and stay on top of everything by bigger z-index.
  • .modal-content with all the content needed, different background color.

Please try the below code to detect where user are clicking in, inside or outside the modal-content.

(function ($) {
    $('.modal').on('click', function (e) {
        //Check whether click on modal-content
        if (e.target !== this)
            return;

        $(this).fadeOut();
    });
})(jQuery);

Upvotes: 5

user2521387
user2521387

Reputation:

You are adding an .on('click'...) to the whole document, I would just add another layer div that acts as a background and a trigger.

Everbody here is thinking too complicated I think, (despite the fact, that the stuff about event bubbling etc. is correct).

Since you have asked for an alternative, this is how I do it:

<!DOCTYPE html>
<html>
<style>

body {
    background: #fff;
    font-family: 'Arial', sans-serif;
    color: #888;
}

#main {
    width: 960px;
    height: 600px;
    margin: auto;
    border: 1px solid #555;
    padding: 20px;
}

.other-content {
    background: #f1f1f1;
    border: 1px solid #f6f6f6;
    padding: 20px;
}

#myModal {
    display: none;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    background: #545454;
}


.modal-inner-content {
    width: 300px;
    margin: 10% auto 0 auto;
    color: #666;
    padding: 20px;
    background: white;
}

</style>
<script>
// All pure, beautiful Vanilla JS
// This is only dumb toggle.. 1 and 0
function toggleModalWindow() {
// For scrollbar Handling
var body = document.getElementById('top')
// first, grab the id of the outer modal window
var modal = document.getElementById('myModal');
// Then get the "status" (open or closed) of that previously declared   variable
var status = modal.getAttribute('data-status');
    // Now we do simple if check if it is open or closed
    if(status === 'closed') {
    // Make the modal block, then manipulate it's opacity slowly
    modal.style.display = "block";
    // We hide the browser sidebar
    body.style.overflowY = "hidden";
    // don't forget to set the attributes again
        modal.setAttribute('data-status', 'open');
    } else {
    modal.style.display = "none";
    // show browser sidebar again
    body.style.overflowY = "visible";
    // don't forget to set the attributes again
    modal.setAttribute('data-status', 'closed');
    }
}

</script>
</head>
<body id="top">
<div id="main">
<div class"other-content">
    <h1>Awesome Content</h1>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quae saepe odio, labore ad, cum repudiandae non officia asperiores. Sequi porro magni corporis.</p>
</div>
<div class="other-content">
    <button onclick="toggleModalWindow();">show me that badASs modal</button>
</div>
<!-- The Modal -->
<div id="myModal" class="modal" data-status="closed" onclick="toggleModalWindow();">
    <!-- Modal content -->
    <div class="modal__content">
        <div class="modal-inner-content">
            <h2>Modal Title</h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorum enim sapiente eius, asperiores ea mollitia velit accusamus soluta similique nobis modi obcaecati veritatis labore temporibus nulla, hic aliquid nam error!</p>
        </div>
    </div>
</div>
</div>
</body>
</html>

Upvotes: 0

Beppe
Beppe

Reputation: 207

Found a working solution. See below.

   $(document).on('click',"#myModal", function(e) {
              e.preventDefault();

              if(e.target.id === "myModal"){
                $('#myModal').fadeOut();
              }
   });

Upvotes: 2

jeremy
jeremy

Reputation: 10057

This is called event bubbling. Because the modal is a child of the document, when the modal is clicked, the event propagates to any parent listeners. This is the by design. To prevent this, you can use event.stopPropagation() on the modal.

For example:

$( document ).on( 'click', function( event ) {
    $( '#myModal' ).fadeOut();
});

$( '#myModal' ).on( 'click', function( event ) {
    event.stopPropagation();
});

It's worth noting that by stopping event propagation, any events that are on parent elements of the modal will also be prevented.

Here is an example of a super basic modal. Honestly, though, you might benefit from looking at better modal design & integration. Having a variable to keep track of whether its open or not would be good. Additionally, an overlay in the background could serve as the only element to assign a listener to. I'm not saying this is the best way.

Upvotes: 5

Shaunak D
Shaunak D

Reputation: 20646

Use a click event on <body>, with event.currentTarget to check for elements.

$('body').on('click',function(e) {
     var $currEl = $(e.currentTarget);
     if(!$currEl.is('#myModal') && !$currEl.closest('#myModal').length){
        $('#myModal').fadeOut();    
     }
     else if(/write code element which triggers modal open even/){
        $('#myModal').fadeIn(); //or any code to trigger modal open 
     }
});
  1. $currEl.is('#myModal') checks if the current clicked elements is myModal
  2. $currEl.closest('#myModal').length checks if the current element in inside/child of myModal

Upvotes: 1

Related Questions