0

I use a function to load a page with jQuery but only after a certain delay after hovering over a li. For that I use setTimeout on the mouseover and try to kill it on the mouseleave if the mouse hovered for less than 500ms over the li. However, the jQuery.ajax still launches, so basically, if I hover over all lis, that will launch plenty of xhr even if I stay only 1ms on the li.

var timer2;
var delay2 = 500;

$('body').on('mouseover','li',function(){

    timer2 = setTimeout(function() {

        var url="res.php";
            jQuery.ajax(
            {
                type: 'POST',
                url:url,
                success: function(data){

                    $('#res').html(data);

                }
            });


    }, delay2);

});
$('body').on('mouseleave', 'li', function() {
    clearTimeout(timer2);
});
Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
john
  • 21
  • 5
  • Try as I may, it's still unclear what your asking or need help with. – Adam Jan 09 '18 at 16:24
  • 1
    @Adam OP wants to fire an ajax call if the mouse stays over an LI for 500ms. Seems the timer is not being cleared if the mouse leaves that element before the timeout fires. – James Thorpe Jan 09 '18 at 16:26
  • 2
    @john - sounds like you have multiple LIs? Is that right? If thats the case, all your timer IDs are overwriting each other as you move around - only the last one will be cancelled. – James Thorpe Jan 09 '18 at 16:27
  • 2
    For a start I'd use classes, scanning the body each time is expensive (depending on how large it is), then, increase the 500ms to something bigger, then put console logs in the mouseenter and leave to make sure they're are behaving as you wish – StudioTime Jan 09 '18 at 16:28
  • @JamesThorpe that's what I thought too, but that should be prevented because `mouseleave` gets called. Unless there's some race condition between the `mouseleave` for one `li` and the `mouseover` for the other. – Federico klez Culloca Jan 09 '18 at 16:30
  • @FedericoklezCulloca Depends on the nesting - might have multiple nested lists etc – James Thorpe Jan 09 '18 at 16:30
  • It works fine, there's obviously something else going on - here it is with simple console log and 2 second timer - same would apply with ajax call - https://jsfiddle.net/au2y7wt8/1/ – StudioTime Jan 09 '18 at 16:44
  • `mouseenter` pairs with `mouseleave`, don't use `mouseover` – freedomn-m Jan 09 '18 at 16:54

4 Answers4

3

Just clear your timeout before setting it again :

var timer2 = null;

$('body').on('mouseover','li',function(){
    clearTimeout(timer2);
    timer2 = setTimeout(function(){ .....

You need to initialize the timeout to null, otherwise you'll get an error can't clear timeout of undefined.

Also, try this to trigger the mouseleave :

$('body').on('mouseover','li',function(){
     // ...
     $(this).off("mouseleave").on("mouseleave", () => clearTimeout(timer2))
});

Edit : Working snippet

var timer2 = null;
var delay2 = 2000;

$('body').on('mouseover', 'li', function() {
  clearTimeout(timer2);
  console.log("Setting timeout...")

  timer2 = setTimeout(() => console.log("Ajax call!"), delay2);

  $(this).off("mouseleave").on('mouseleave', () => {
    console.log("Clearing timeout.")
    clearTimeout(timer2);
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<li>Hover over me</li>
<li>Over me too</li>
Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
  • If there's only one `
  • ` how will this help? The problem sounds like the `mouseleave` is not doing what it should
  • – StudioTime Jan 09 '18 at 16:31
  • @DarrenSweeney why do you think there's only one `li`? Relevant part of the question: "if I hover over all `li`s" – Federico klez Culloca Jan 09 '18 at 16:32
  • Hmmm... Make sense, I think I misunderstood the question – Jeremy Thille Jan 09 '18 at 16:33
  • I think your issue is more based on the HTML markup than this code. You probably want mouseenter, not mouseover. https://stackoverflow.com/questions/7286532/jquery-mouseenter-vs-mouseover – epascarello Jan 09 '18 at 16:35
  • @DarrenSweeney Added a suggestion about the `mouseleave`. – Jeremy Thille Jan 09 '18 at 16:36
  • Testing this still trigger the timer occasionally in jsFiddle and I'm inclined to thing it is the binding having to traverse through the DOM which easily can impact a 500millisecond timer. Bindings might be better of to bind to a closer static element than `body` – Nope Jan 09 '18 at 16:38
  • ...not anymore :) – Jeremy Thille Jan 09 '18 at 16:38
  • @FedericoklezCulloca Ok, I'll rephrase - if the OP hovers over only one `
  • ` how will this help?
  • – StudioTime Jan 09 '18 at 16:39
  • @DarrenSweeney ok, got it :) – Federico klez Culloca Jan 09 '18 at 16:40