Reputation: 150
I'm trying to get my head around to understand how to use closures in connection with jQuery event functions.
My current problem is to round shapes on the screen and make them stop and fade on mouseover and fade and restart on mouse out. I've to use imagemaps to create a round mouseover sensitive area. While the animation works fine I'm having trouble to make use of closures on the mouseover function as i would like it to be.
Given this setup:
(function($){
$.fn.xyz = function( option ) {
// override defaults with specified option
option = $.extend( {}, $.fn.xyz.option, option );
return this.each(function(index, element) {
// run works fine.
function run(index) {
$(".ball:eq(" + index + ")").css({top: 500).startAnimation({ top: -500}, 1000, "linear", (function (i) {
return function() {
run(i);
}})(index));
}
//1 this version works great but I don't like the .parent().parent() especially as the animation requires
// just the ball I hover over gets the opacity assigned
$("area").mouseover(
function () {$(this).parent().parent().css('opacity', 0.5);}
);
//2 this version makes all balls transparent on page load
$("area").mouseover(
(function (activeElement) {
$(activeElement).css('opacity', 0.5);
})(this)
);
//3 this version makes all balls transparent on the first mouse over event
$("area").mouseover(
(function (activeElement) {
return function() {
$(activeElement).css('opacity', 0.5);
}
})(this)
);
//4 also this version affecs all balls and not just the one that is mouse overed
var activeBall = $(this);
$("area").mouseover(function () {
$(activeBall).css('opacity', 0.5);
}).mouseout(function () {
$(activeBall).css('opacity', 1);
});
run(index);
});
},
$.fn.xyz.option = {};
})(jQuery);
Why does version 2, 3, and 4 target all elements and not just the one which is actively hovered over. How would I make use of closures to have to avoid to make use of indexes or similar workarounds?
Many thanks!
Upvotes: 0
Views: 1192
Reputation: 39818
You made it a Self Invoking Anonymous Function. Basically, called it automagically with the jQuery object. You also wrapped functions in functions...which I don't get. This should work:
(function($){
$.fn.xyz = function( option ) {
// override defaults with specified option
option = $.extend( {}, $.fn.xyz.option, option );
return this.each(function(index, element) {
// run works fine.
function run(index) {
$(".ball:eq(" + index + ")").css({top: 500).startAnimation({ top: -500}, 1000, "linear", (function (i) {
return function() {
run(i);
}})(index));
}
//1 this version works great but I don't like the .parent().parent() especially as the animation requires
// just the ball I hover over gets the opacity assigned
$("area").mouseover(
function () {$(this).parent().parent().css('opacity', 0.5);}
);
//2 this version makes all balls transparent on page load
$("area").mouseover(
(function (activeElement) {
$(activeElement).css('opacity', 0.5);
})
);
//3 this version makes all balls transparent on the first mouse over event
$("area").mouseover(
(function (activeElement) {
return function() {
$(activeElement).css('opacity', 0.5);
}
})
);
//4 also this version affecs all balls and not just the one that is mouse overed
var activeBall = $(this);
$("area").mouseover(function () {
$(activeBall).css('opacity', 0.5);
}).mouseout(function () {
$(activeBall).css('opacity', 1);
});
run(index);
});
},
$.fn.xyz.option = {};
})(jQuery);
Basically, SIAF is doing things like this:
(function(txt) { alert(txt); })('Hello world!');
You declare an anonymous function (it has no name), which accepts a parameter, and then with the parentheses at the end, you call it, and what's in the parens are the function's parameters.
So, when you said
(function (activeElement) {
return function() {
$(activeElement).css('opacity', 0.5);
}
})(this)
The compiler saw "activate the function with the this object as parameter". Seeing as how this would refer outside your declared function to the jQuery object, jQuery saw it as "change all elements I have with the .css function".
Upvotes: 1