-1

I am having an issue with on mouse enter and mouse leave events, it triggers fine the first time but if I trigger the event again before the animation finishes such as within a 1 second interval the animation is performed twice. The async nature of javascript is causing the event loop to store each event in a queue until it finishes all the events triggered. How can I prevent this? I can provide more information if needed but I really can't seem to solve this at all...I may need to rethink my approach to the design and all suggestions are welcome but I would really like to get this to work....

I have tried this and it still keeps queueing:

  $('div#nav-sidebar').off('mouseleave').on('mouseleave', mouseLeaveEvent);

  $('div#nav-sidebar').off('mouseenter').on('mouseenter', mouseEnterEvent);

HTML

enter image description here

Current Code below....

var mouseLeaveEvent = function() {
     console.log('sidebar mouse leave!')
        $('li#GlasswareCandles').children('ul.menu-items').slideUp(750);
        $('li#CandleTins').children('ul.menu-items').slideUp(750);
        $('li#ScentedOils').children('ul.menu-items').slideUp(750);
        $('li#Air-Fresheners').children('ul.menu-items').slideUp(750);
        $('li#OtherProducts').children('ul.menu-items').slideUp(750);
        $(this).children('ul.blog_list.toggle_list').slideUp(1500);
        return false;
};

var mouseEnterEvent = function() {
      console.log('sidebar mouse enter!')
        $(this).children('ul.blog_list.toggle_list').slideDown(500);
        return false;
};

$('div#nav-sidebar').off('mouseleave').on('mouseleave', mouseLeaveEvent);

$('div#nav-sidebar').off('mouseenter').on('mouseenter', mouseEnterEvent);
Grim
  • 2,398
  • 4
  • 35
  • 54

3 Answers3

1

Why this happens

Because of the async nature of jQuery animations, every new animation is added to a queue.

How to solve this

You could try to use .stop() to clear the queue.

From the documentation:

When .stop() is called on an element, the currently-running animation (if any) is immediately stopped. If, for instance, an element is being hidden with .slideUp() when .stop() is called, the element will now still be displayed, but will be a fraction of its previous height. Callback functions are not called.

If more than one animation method is called on the same element, the later animations are placed in the effects queue for the element. These animations will not begin until the first one completes. When .stop() is called, the next animation in the queue begins immediately. If the clearQueue parameter is provided with a value of true, then the rest of the animations in the queue are removed and never run.

If the jumpToEnd argument is provided with a value of true, the current animation stops, but the element is immediately given its target values for each CSS property. In our above .slideUp() example, the element would be immediately hidden. The callback function is then immediately called, if provided.

My attempt to solve the problem

From your code, I assume that you want to do something when hovered? I made a JSFiddle with the code you gave us. I tried to make something that could resemble your intention. However, without a lot of code, it becomes a bit hard.

See the following code snippet(s).

var mouseLeaveEvent = function() {
  // Replaced the several separate calls with one call, hope you don't mind
  $('li.tab').children('ul.menu-items').stop().slideUp(750);
  $(this).children('ul.blog_list.toggle_list').stop().slideUp(1500);
  return false;
};

var mouseEnterEvent = function() {
  $(this).children('ul.blog_list.toggle_list').stop().slideDown(500);
  return false;
};

// While I was working and testing, it was easier to implement a slideDown 
// for all of the elements on the toggle by clicking it
$('h4.toggle').click(function() {
  $('div#nav-sidebar').find('li.tab').children('ul.menu-items').slideDown(500);
});

// This replaces the separate calls to register mouse enter and exit
$('div#nav-sidebar').hover(mouseEnterEvent, mouseLeaveEvent);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="nav-sidebar" style="display: block;">
  <h4 class="toggle" style="width: 85px;">Toggle</h4>
  <ul class="blog_list toggle_list">
    <li id="GlasswareCandles" class="tab">
      <a class="active main-tab" role="button" tilte="Glassware Candles">Glassware Candles</a>
      <ul class="menu-items">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
      </ul>
    </li>
    <li id="CandleTins" class="tab">
      <a class="active main-tab" role="button" tilte="Candle Tins">Candle Tins</a>
      <ul class="menu-items">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
      </ul>
    </li>
    <li id="ScentedOils" class="tab">
      <a class="active main-tab" role="button" tilte="Scented Oils">Scented Oils</a>
      <ul class="menu-items">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
      </ul>
    </li>
    <li id="Air-Fresheners" class="tab">
      <a class="active main-tab" role="button" tilte="Air-Fresheners">Air-Fresheners</a>
      <ul class="menu-items">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
      </ul>
    </li>
    <li id="WaxMelts" class="tab">
      <a class="active main-tab" role="button" tilte="Wax Melts">Wax Melts</a>
      <ul class="menu-items">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
      </ul>
    </li>
    <li id="OtherProducts" class="tab">
      <a class="active main-tab" role="button" tilte="OtherProducts">OtherProducts</a>
      <ul class="menu-items">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
      </ul>
    </li>
  </ul>
</div>

What did I do?

I changed the calls to have .stop, which allows just one queue of animations to run at a time. To have more details, go to the aforementioned documentation.

I also changed the separate calls to register the mouse events to one by using .hover( enterFunction, leaveFunction ), and I changed the separate calls to children to be more compact. Did this mainly for readability.

I added a way to expand the items, did this because it was easier to test while working on it.


I really hope this solved your problem. If you need more information or I understood the problem incorrectly, just let me know.

Community
  • 1
  • 1
Bart Koppelmans
  • 195
  • 1
  • 11
0

$("div#nav-sidebar").off("mouseleave");
$("div#nav-sidebar").off("mouseenter");

var mouse - leave - event = function() {
  console.log('sidebar mouse leave!')
  $('li#GlasswareCandles').children('ul.menu-items').slideUp(750);
  $('li#CandleTins').children('ul.menu-items').slideUp(750);
  $('li#ScentedOils').children('ul.menu-items').slideUp(750);
  $('li#Air-Fresheners').children('ul.menu-items').slideUp(750);
  $('li#OtherProducts').children('ul.menu-items').slideUp(750);
  $(this).children('ul.blog_list.toggle_list').slideUp(1500);
  $('h4.toggle').animate({
    width: 0
  }, {
    duration: 1500,
    complete: function() {
      sidebar.style.display = 'none';
      $('img#sidebar-placeholder').show();
    }
  });
  return false;
}

$('div#nav-sidebar').on('mouseleave', mouse - leave - event);

var mouse - enter - event = function() {
  console.log('sidebar mouse enter!')
  $(this).children('ul.blog_list.toggle_list').slideDown(500);
  return false;
}

$('div#nav-sidebar').on('mouseenter', mouse - enter - event);

You can just make your events off by using the above snippets after your animation, and then you can register the events again.

Alireza
  • 100,211
  • 27
  • 269
  • 172
Hassan Abbas
  • 1,166
  • 20
  • 47
  • this doesn't work at all. Tried multiple ways of using off and it doesn't work. The events are still added to a queue and executed. – Grim Jun 21 '16 at 18:25
0

You can have a look at this example. It works perfectly on my website. http://stark-cove-24150.herokuapp.com

 $(document).ready(function(){
 $("#designer").mouseenter(function(){
     $("#xyz").attr("src", "design.jpg");
     $("#face").css("background-image", "url(des2.jpg)");
     $("#coder").css("opacity", "0.5");
 });
 $("#designer").mouseleave(function(){
     $("#xyz").attr("src", "def.jpg");
     $("#coder").css("opacity", "");
 });
 $("#coder").mouseenter(function(){
     $("#xyz").attr("src", "cp2.jpg");
      $("#designer").css("opacity", "0.5");
      $("#face").css("background-image", "url(coding.jpg)");
 });
 $("#coder").mouseleave(function(){
     $("#xyz").attr("src", "def.jpg");
     $("#face").css("background-image", "url()");
     $("#designer").css("opacity", "");
 });
 });
  • the mouse leave and mouse enter events perform as expected its just when you trigger the event more than once within a one second interval. Its a timing thing related to the async nature of javascript queueing each event. – Grim Jun 23 '16 at 12:34
  • I reworded the description above to try to make it more clear of whats happening. – Grim Jun 23 '16 at 12:43