javascriptalpine.js

How to interrupt the timeout that hides the toast?


I'm showing a toast alert, controlling visibility with alpinejs, and want the alert to dim after a couple of seconds and be hidden after some more seconds unless the mouse hovers over it.
I got the dimming working, but don't know how to interrupt the timeout that hides the element.

<div
  x-data="{visible: true, dimmed: false}"
  x-show="visible"
  x-effect="setTimeout(() => dimmed = true, 5000);setTimeout(() => visible = false, 10000)"
  x-on:mouseover="dimmed = false"  // <-- How can I stop the second setTimeout() here?
  x-transition.duration.500ms
  :class="dimmed ? 'opacity-60' : 'opacity-100'"
  class="flex alert alert-info justify-between">
    <div>Some message here</div>
    <div x-on:click="visible = false">
      <button class="btn btn-sm btn-square btn-info">
        Close
      </button>
    </div>
</div>

In js I would declare a variable for the setTimeout() and then call cancelTimeout() on that variable but I don't know how to do this using alpine.

Additionally want to restart the setTimeout() once the mouse leaves the <div>. I guess this could easily be done by defining another setTimeout in x-data and then calling that @onmouseleave, but I can't figure out how to interrupt the timeout in the first place.


Solution

  • Do something like this, add a mouse over and mouse leave event that can start/stop the timer. Mouse over can call a function to stop the timer and mouse leave can do the inverse.

    <div
      x-data="toast()"
      x-show="visible"
      x-transition.duration.500ms
      :class="dimmed ? 'opacity-60' : 'opacity-100'"
      class="flex alert alert-info justify-between"
      x-init="startTimers()"
      x-on:mouseover="cancelTimers(); dimmed = false"
      x-on:mouseleave="startTimers()"
    >
      <div>Some message here</div>
      <div x-on:click="visible = false">
        <button class="btn btn-sm btn-square btn-info">
          Close
        </button>
      </div>
    </div>
    

    <script> part:

    function toast() {
      return {
        visible: true,
        dimmed: false,
        dimTimeout: null,
        hideTimeout: null,
        startTimers() {
          this.cancelTimers();
          this.dimTimeout  = setTimeout(() => this.dimmed = true  , 5000);
          this.hideTimeout = setTimeout(() => this.visible = false, 10000);
        },
        cancelTimers() {
          clearTimeout(this.dimTimeout);
          clearTimeout(this.hideTimeout);
        }
      }
    }