1

I am using jQuery to loop an addClass and removeClass function on a list ul.

$(function () {
  var $looped = $('li');

  (function _loop(idx) {
    $looped.removeClass('current').eq(idx).addClass('current');
    setTimeout(function () {
      _loop((idx + 1) % $looped.length);
    }, 1000);
  }(0));
});

I want to stop this loop while I am hovering the element with .mouseenter() to let the user control this example on his own.

JSFiddle Demo View

This is quite easy to achieve with Tobia Pause Plugin, but sadly this does only work for animate() loops. I appreciate every hint or tip!

Marian Rick
  • 3,350
  • 4
  • 31
  • 67
  • 1
    http://jsfiddle.net/bdpcfuhy/ clearTimeout – Satpal Feb 13 '15 at 18:21
  • You might want to check this post, as it offers a way to pause and resume timeouts rather than just clear them: http://stackoverflow.com/questions/3969475/javascript-pause-settimeout – martskins Feb 13 '15 at 18:26

2 Answers2

1

In this example, I've shown how to pause and restart the animation on a hover() event. This also restarts the animation exactly where it left off.

$(function () {
    var $looped = $('li');
    var timeOut;
    var index = 0;
    function _loop(idx) {
        $looped.removeClass('current').eq(idx).addClass('current');
        timeOut = setTimeout(function () {
            index = (idx + 1) % $looped.length;
            _loop(index);
        }, 1000);
    };
    _loop(index);
    $("ul").hover(function () {
        window.clearTimeout(timeOut);
    }, function () {
        _loop(index);
    });
    $("li").hover(function () {
        $("li").removeClass("current");
        $(this).addClass("current");
    }, function () {
        $("li").removeClass("current");
    });
});

There's a few key points.

First - I assign a function-scoped variable (not global) within the anonymous function that tracks the timeout function. This allows me to clear it at a later time within that function. It's typically a bad idea to clutter up the global namespace unnecessarily.

Second - I changed the mouseenter() function to a hover() function, which accepts two functions as parameters, one for the mouse over, and one for the mouse out events.

Third - I added in a variable called index which is going to keep track of the index for us throughout the function. This allows the loop to resume exactly where it left off when the mouse is no longer over the element.

See the Fiddle HERE

Howard Renollet
  • 4,609
  • 1
  • 24
  • 31
  • hey @nanndoj, thanks a lot for your answer. You nearly got it right: I want to stop the animation as soon as I hover the whole `ul`, not the nested `li`. I tried to adopt your script, which works fine for me: http://jsfiddle.net/mwnv6zjt/11/ If you want to update your answer feel free to correct this your own way. Best regards and thanks a lot! – Marian Rick Feb 13 '15 at 18:54
  • @MarianRick - the code you provided indicated the `mouseenter` event was on the `li` not the `ul`. code has been updated – Howard Renollet Feb 13 '15 at 18:55
  • Actually it is, and it works fine for this minimized example. But with a more complex setting it is useful to stop the animation as soon I enter the whole `ul` as described in my question and fiddle, because otherwise the animation starts and stops each time your mouse enters the `margin` between my `li` elements. This creates some flickering (if you test it yourself)! – Marian Rick Feb 13 '15 at 18:58
  • @MarianRick - I caught that after my previous comment. My answer and example has been updated. Thanks! – Howard Renollet Feb 13 '15 at 19:00
  • the idea of starting the animation where it paused is in some cases useful, but in my example its quite annoying. I am trying to remove this. You have created `index` to count where the action takes places. I would like to set `index` to the value of the `li`s number (like the fourth li sets the index to `index (4)` so that the animation continues where the user has left the hover! I can't make it work. Can you help me once again? – Marian Rick Feb 14 '15 at 12:48
0

I suppose you want to start the animation again after mouseout as you said "stop while I am hovering". So first I have made your setTimeout global:

(function _loop(idx) {
    $looped.removeClass('current').eq(idx).addClass('current');
    window.animate = function () {
      _loop((idx + 1) % $looped.length);
    }
    window.timeout = setTimeout(animate, 1000);
}(0));

Then I modified your hover function to add again the event after mouseout UL:

$("ul").on("mouseenter",function() {
    clearTimeout(timeout);
    $(this).one("mouseout", function() {
      window.timeout = setTimeout(animate, 1000);
    })
})

Note that I used .one() to attach the mouseout event because I don't want to add many timeouts at the same time.

I changed your FIDDLE

nanndoj
  • 6,580
  • 7
  • 30
  • 42
  • hey @nanndoj, thanks a lot for your answer. You nearly got it right: I want to stop the animation as soon as I hover the whole `ul`, not the nested `li`. I tried to adopt your script, which works fine for `mouseenter()`, but as soon as I leave a `li` the animation starts again (while I did **not** leave the `ul`). http://jsfiddle.net/mwnv6zjt/9/ If you have a suggestion I would really appreciate it! – Marian Rick Feb 13 '15 at 18:49
  • @MarianRick - just change `$(this).one("mouseout", function() {` to `$(this).parent().one("mouseout", function() {` – Howard Renollet Feb 13 '15 at 18:52
  • FYI - it's not the best practice to clutter the global namespace unnecessarily. – Howard Renollet Feb 13 '15 at 18:54
  • @HowardRenollet I know and I totally agree. I'm just keeping focus on answer the question. I also modified using .on() instead of .mouseenter() – nanndoj Feb 13 '15 at 18:57
  • `mouseenter()` is the same as `.on( "mouseenter", handler )`, it's just a shortcut. Per the [jQuery Docs](http://api.jquery.com/mouseenter/) – Howard Renollet Feb 13 '15 at 19:04