All,
See the code below:
function menu() {
this.menuitem=[];
this.submenu=[];
this.menuitem[0] = $('div#sivname1');
this.menuitem[1] = $('div#divname2');
this.submenu[0] = $('div#submenu1');
this.submenu[1] = $('div#submenu2');
this.active = false;
this.timeout;
}
menu.prototype = {
animatedown: function(submenu) {
submenu.animate({top: '99px'}, 200);
},
animateup: function(submenu) {
submenu.animate({top: '-4px'}, 200);
}
}
var menu = new menu();
z=2;
while(z--) {
console.log(z);
menu.menuitem[z].hover(
function() { //mouseover
if(menu.active) {
clearTimeout(menu.submenu[z].data("timeout"));
}
else {
menu.animatedown(menu.submenu[z])
};
},
function() { //mouseleave
$(this).data("timeout", setTimeout(function({
menu.animateup(menu.submenu[z])
},200));
menu.active = false;
}),
menu.submenu[z].hover(
function() { //mouseover
menu.active = true;
if (menu.menuitem[z].data("timeout")) {
clearTimeout(menu.menuitem[z].data("timeout"));
};
},
function() { //mouseleave
$(this).data("timeout", setTimeout(function() {
menu.animateup(menu.submenu[z]);menu.active = false;
},200));
});
}
This code gives the following error:
Uncaught TypeError: Cannot call method ‘animate’ of undefined
And the strange this is that is I add:
z=0;
to the bottom of the code it will work properly. I would expect it to work without z=0 and I have no idea why it does when I add that. Can anyone please explain?
The problem was in the closures, the following code works:
z=1;
while(z--){
(function(z) {
console.log(z);
menu.menuitem[z].hover(
function(){ //mouseover
if(menu.active){clearTimeout(menu.submenu[z].data("timeout"));}
else{menu.animatedown(menu.submenu[z])};
},
function(){ //mouseleave
$(this).data("timeout", setTimeout(function(){menu.animateup(menu.submenu[z])},200));
menu.active = false;
}
)
menu.submenu[z].hover(
function(){ //mouseover
menu.active = true;
if(menu.menuitem[z].data("timeout")){clearTimeout(menu.menuitem[z].data("timeout"));};
},
function(){ //mouseleave
$(this).data("timeout", setTimeout(function(){menu.animateup(menu.submenu[z]);menu.active = false;},200));
}
);
})(z); //this is to enable closures http://bonsaiden.github.com/JavaScript-Garden/#function.closures
}
First of all, you have an error in the code:
Should be:
Second:
zis global, and your callbacks will use it’s last value after the initialization. You should create a local copy ofzfor your callbacks with a closure in the loop, like this:This way you enclose the value of
zfor that while cycle, and the callbacks in it.The strange thing with
z=0is that, when the loop dies (sincezis 0) the decrementing operator will run one more time, andzwill be -1. The -1 index will be used in all your callbacks, indexing a non-object which don’t have animate ofc. But (!) if you set itz=0, than it will index an object, but always the one with the 0 index. You have to use the above correction to get the good result in every menuitem.