July 19, 2011

jQuery weird mouseenter and mouseleave events

So jQuery is all-mighty but like any god is full of flaws... one of them is with the event.type when you are using "mouseenter" or "mouseleave",

This works fines:

$("body").bind("mouseenter",function(event){
 if(event.type == "mouseenter"){
  alert("OK")
 }
})

But in this other case the alert never gets executed

$("body").bind("mouseenter",function(event){
 setTimeout(function(){
  if(event.type == "mouseenter"){
   alert("OK")
  }
 })
})


That is because when the variable event is called inside a setTimeout (or setInterval) it returns "mouseover" instead of "mouseenter" as it should.

So just save the actual event type and you will be just fine.

$("body").bind("mouseenter",function(event){
 var eventType = event.type
 setTimeout(function(){
  if(eventType == "mouseenter"){
   alert("Mouse inside... i can feel it inside of me!")
  }
 })
})

5 comments:

  1. This is not a flaw in jQuery, but in javascript closures.

    ReplyDelete
  2. Mmm... the point of jQuery is to fix all the javascript mess, so i think is a jQuery bug too. It would be easy to fix it by return a copy of the variable 'event' rather than a real reference.

    ReplyDelete
  3. There is no flaw in jQuery and there is no flaw in javascript closures.

    The code you show there will do what you have coded it to do, no more, no less. The result is not what you think it should be but that is only because of your misunderstood of javascript closures and variables scope.

    Just read:
    http://robertnyman.com/2008/10/09/explaining-javascript-scope-and-closures/
    if you want to understand how it works.

    Even your solution is a bad solution because still has a problem in the concept of closures and variables scope. Look at this minor change to your last code that breaks your solution though you probably think it should work.

    $("body").bind("mouseenter",function(event){
    var eventType = event.type;
    setTimeout(function(){
    if(eventType == "mouseenter"){
    alert("Mouse inside... i can feel it inside of me!")
    } else {
    alert("I can't feel anything because eventType is: " + eventType);
    }
    });
    eventType = "im not the mouse event type any more";
    });

    ReplyDelete
  4. I don't think it should work; setTimeout is to do something after.

    ReplyDelete
  5. But it hasn't anything to do with setTimeout but with closures and variable scope. The problem is in how you are using the closure inside setTimeout not in setTimeout itself. I suppose anyone understand that setTimeout was only an example to try to explain a flaw in jQuery. But that flaw does not exist at all. If we change the code to something correct, then it works.

    var enter = function(eventType) {
    if(eventType == "mouseenter"){
    alert("Mouse inside... i can feel it inside of me!")
    } else {
    alert("I can't feel anything because eventType is: " + eventType);
    }
    }

    window.onload = function() {
    $("body").bind("mouseenter",function(event){
    var eventType = event.type;
    setTimeout(enter(eventType));
    eventType = "im not the mouse event type any more";
    });
    }

    There is nothing wrong with jQuery nor with javascript closures. Just use javascript closures correctly. I suggest you to read that article I'm linking or any other article explaining that topic.

    ReplyDelete

You can use [CODE][/CODE] to post Javascript code.
You can start a sentence with ">" to make a quotation.