0

I have a Bootstrap modal that needs to be triggered when the user navigates away from the page. In plain JS the solution is to listen for the mouseleave event, check if the user has manually closed the modal before, and if not, show the modal.

document.addEventListener("mouseleave", function (e) {
        if (e.clientY < 0) {
          if (localStorage.getItem('newsLetterSignUp') === null) {
            $('someModal').modal();
          }
        }
      }, false);

I'm trying to achieve the same behaviour with Apline.js.

The first approach was to set the event handler on the modal itself: (I have a custom model CSS class .newsletter-modal instead of Bootstrap's .modal because I want to handle the visibility with Alpine)

<div x-data="newsletter()">
    <div
      x-show="showModal"
      @mouseleave.document="revealModal"
      class="newsletter-modal show fade"
      id="mailingListModal"
      tabindex="-1"
      role="dialog"
      aria-labelledby="mailingListModal"
      aria-hidden="true"
    >
      <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content" @click.away="showModal = false"> [modal content] </div>
      </div>
  </div>

 <--- JS code to handle the modal actions --->
    <script>
    window.newsletter = function() {
      return {
        showModal: true,
        revealModal(e) {
          alert('leave');
          if (e.clientY < 0 && localStorage.getItem('newsLetterSignUp') === null) {
            this.showModal = true;
          }
        },
        closeNewsletterModal() {
          this.showModal = false;
          localStorage.setItem('newsLetterSignUp', JSON.stringify(new Date()));
        }
      }
    }
  </script>
        

My idea was to add the .document property to the @mouseleave event in order to bind it to the document, but this had no effect.

Another approach was to set the @mouseleave event on the , dispatch an event and listen for the event on the modal. But this also did not cause the event to be fired on mouseleave.

SdeWijs
  • 140
  • 11
  • I found that using the mouseout event does trigger the event, but the issue with mouseout is that it is also triggered on children of the element it's bound to. – SdeWijs Oct 04 '20 at 13:20

1 Answers1

0

It turned out the issue was not in the event handler or Alpine, but Firefox. In Firefox, the mouseleave event is not triggered when the user navigates the mouse away from the window. The behaviour is explained in this question

So the solution for Firefox was to add an extra event listener that tracks the mouse movement. And trigger as soon as the e.clientY < 10

// HTML
<div x-data="newsletter()" @mouseleave.window="revealModal" @mousemove.document="isUserLeaving"> ... </div>
// JS
isUserLeaving(e) {
   if (e.clientY < 10) {
       this.revealModal();
   }
}
SdeWijs
  • 140
  • 11