Search code examples
javascriptstoppropagation

Stop propogation of event listener click but still allow other click events to occur within the element


I have created a fairly classic modal. Fixed modal in the middle of the screen. Semi-transparent background and a box in the middle.

The box contains some click event listeners (e.g a close X and a button that performs another action).

I want to allow the user to close the modal by clicking on the outer background.

HTML example

<div class="modal">
    <div class="modal__inner">
        <div class="modal_closebtn">X</div>
    </div>
</div>

Currently, I have the following to handle closing the modal based on click of .modal, which covers the whole screen.

document.querySelector(".modal").addEventListener("click", () => {
    this.toggleModal();
});

My problem is, this fires if you click inside the .modal__inner too.

So I tried adding an eventListener to stopPropagation()

document.querySelector(".modal__inner").addEventListener("click", e => {
    e.stopPropagation();
});

This now blocks the eventListener for my .modal_closebtn and any other events that occur inside the modal.

How can I ensure that the click for the background div only works on the modal div not modal__inner or any others? Unfortunately when I review e.currentTarget after clicking inside my div it returns .modal not .modal__inner even though it does appear that I clicked inside that div.

Non jQuery solution please


Solution

  • To avoid the execution of querySelector too many times and gain a little of performance, store that result into a variable.

    var elem = document.querySelector(".modal")
    elem.addEventListener("click", (e) => {
      if (e.target !== elem) return;
      console.log('toggle!');
      //this.toggleModal();
    });
    .modal {
      width: 300px
      height: 300px;
      border: 1px solid #000
    }
    
    .modal__inner {
      width: 100px
      height: 100px;
      border: 1px solid red
    }
    <div id="hola" class="modal">
      Parent modal
      <br>
      <br>
     
      <br>
      <div id="epale" class="modal__inner">
        Inner modal
        <div class="modal_closebtn">X</div>
      </div>
    </div>

    Happy coding!