Franz Wilding
Franz Wilding

Reputation: 33

jquery timeout-function never called on mouseenter mouseleave

I'm having a little problem with the setTimeout-function.

$(this) is every DOM-Element with a specific class.

When the mouse enters an elememt, and then leave it, there is no problem. But when the mouse leaves an element directly to another (within the 500ms timeout) the first element (that one, the mouse left from) never fades out.

So the new mouseenter-Event kind of prevent the timeOut to call the function. Without the setTimeout-wrapper everything is just working fine.

Here's my code:

$(this).hover(methods['mouseenterManager'], methods['mouseleaveManager']);


/**
 * manage mouseenter events
 */
mouseenterManager: function() {

    clearTimeout(timer);

    //create toolbar, if no toolbar is in dom
    if ($(this).data("layouter").toolbar == undefined) {

        //get bottom center of this element
        pos_left = ($(this).width() / 2) + $(this).offset().left;
        pos_top = $(this).height() + $(this).offset().top;

        //create toolbar element
        toolbar = $('<div style="display:none; left:' + parseInt(pos_left) + 'px; top:' + parseInt(pos_top) + 'px;" class="layouter_bar"><ul><li><a class="edit" href="javascript:;">Edit</a></li><li><a class="copy" href="javascript:;">Edit</a></li><li><a class="remove" href="javascript:;">Edit</a></li></ul></div>');

        //bind this element to toolbar
        toolbar.data("layouter", {
            parent: $(this),
        });

        //bind toolbar to this element
        data = $(this).data("layouter");
        data.toolbar = toolbar;
        $(this).data("layouter", data);

        //bind this element to toolbar
        data = toolbar.data("layouter");
        data.parent = $(this);
        toolbar.data("layouter", data);

        element = $(this);
        toolbar.mouseleave(function() {

            toolbar = $(this);
            timer = setTimeout(function() {
                if (!toolbar.is(":hover") && !element.is(":hover")) {

                    toolbar.fadeOut("fast", function() {
                        $(this).remove();
                    });

                    data = element.data("layouter");
                    data.toolbar = undefined;
                    element.data("layouter", data);
                }
            }, 500);
        });

        //display the toolbar  
        $("body").append(toolbar);
        toolbar.fadeIn("fast");
    }
},


/**
 * manage mouseleave events
 */
mouseleaveManager: function() {

    toolbar = $(this).data("layouter").toolbar;
    element = $(this);
    if (toolbar != undefined) {
        timer = setTimeout(function() {
            if (!toolbar.is(":hover")) {

                toolbar.fadeOut("fast", function() {
                    $(this).remove();
                });

                data = element.data("layouter");
                data.toolbar = undefined;
                element.data("layouter", data);
            }
        }, 500);
    }
},

};​

Any ideas?

thank you!

Upvotes: 0

Views: 255

Answers (2)

jfriend00
jfriend00

Reputation: 707876

It looks to me like you're using a lot of global variables and when you go into another element, the value of all those global variables gets changed. Your timeout function is referencing those global variables so it doesn't work properly when they've been changed by entering another element.

It also looks to me like as soon as you enter another element, you clear the timer to prevent it from running and since it's a global timer, there is only one so you have killed the timer that you want to fire.

For the global variable problem, put var in front of all variables that should be local like this:

var toolbar = $(this).data("layouter").toolbar;
var element = $(this);

and

//get bottom center of this element
var pos_left = ($(this).width() / 2) + $(this).offset().left;
var pos_top = $(this).height() + $(this).offset().top;

For the timer issue, it appears to me like you need to NOT have a single global timer, but need a timer for each element. That is a bit more complicated. Without something I can run and test, I can't be sure if this works without any other changes, but this is steps in the right direction to fix the variables to be local and to make the timer be local for each element:

$(this).hover(methods['mouseenterManager'], methods['mouseleaveManager']);


/**
 * manage mouseenter events
 */
mouseenterManager: function() {

    var self = $(this);
    var timer = self.data("timer");
    if (timer) {
        clearTimeout(timer);
    }

    //create toolbar, if no toolbar is in dom
    if (self.data("layouter").toolbar == undefined) {

        //get bottom center of this element
        var pos_left = ($(this).width() / 2) + $(this).offset().left;
        var pos_top = $(this).height() + $(this).offset().top;

        //create toolbar element
        var toolbar = $('<div style="display:none; left:' + parseInt(pos_left) + 'px; top:' + parseInt(pos_top) + 'px;" class="layouter_bar"><ul><li><a class="edit" href="javascript:;">Edit</a></li><li><a class="copy" href="javascript:;">Edit</a></li><li><a class="remove" href="javascript:;">Edit</a></li></ul></div>');

        //bind this element to toolbar
        toolbar.data("layouter", {
            parent: self,
        });

        //bind toolbar to this element
        var data = self.data("layouter");
        data.toolbar = toolbar;
        self.data("layouter", data);

        //bind this element to toolbar
        data = toolbar.data("layouter");
        data.parent = self;
        toolbar.data("layouter", data);

        var element = self;
        toolbar.mouseleave(function() {

            toolbar = self;
            timer = setTimeout(function() {
                self.data("timer", null);
                if (!toolbar.is(":hover") && !element.is(":hover")) {

                    toolbar.fadeOut("fast", function() {
                        $(this).remove();
                    });

                    data = element.data("layouter");
                    data.toolbar = undefined;
                    element.data("layouter", data);
                }
            }, 500);
            self.data("timer", timer);
        });

        //display the toolbar  
        $("body").append(toolbar);
        toolbar.fadeIn("fast");
    }
},


/**
 * manage mouseleave events
 */
mouseleaveManager: function() {

    var toolbar = $(this).data("layouter").toolbar;
    var element = $(this);
    var timer = element.data("timer");
    if (toolbar != undefined && !timer) {
        timer = setTimeout(function() {
            element.data("timer", null);
            if (!toolbar.is(":hover")) {

                toolbar.fadeOut("fast", function() {
                    $(this).remove();
                });

                var data = element.data("layouter");
                data.toolbar = undefined;
                element.data("layouter", data);
            }
        }, 500);
        element.data("timer", timer);
    }
},

};​

Upvotes: 0

Machiel
Machiel

Reputation: 1515

Pass the elements you want to edit to the function of the timer.

For example:

timer = setTimeout(function(toolbar, element) {
        if (!toolbar.is(":hover")) {

            toolbar.fadeOut("fast", function() {
                toolbar.remove();
            });

            data = element.data("layouter");
            data.toolbar = undefined;
            element.data("layouter", data);
        }
    }, 500)

Upvotes: 0

Related Questions