jQuery Tipsy won't work with jQuery.each() and live:true
Question by papaiatis
Note: This question was marked as solved once, but it figured out that upgrading to the latest jQuery was fixed only one issue. Please see the updated question below for the remaining issue.
Hi all,
I have just run into a weird issue with jQuery.Tipsy.
Here’s a simplified demo fiddle: http://jsfiddle.net/6nWtx/7/
As you can see, the lastly added a.tipsy2
element does not get tipsyfied. The .tipsy2
elements are being tipsyfied within a jQuery.each()
function and at this point I have the problem. Without the each()
it works. Unfortunately, I need .each()
to iterate through the elements to do some other stuff before I call tipsy()
.
Any suggestion?
Here’s the source code of Tipsy: https://github.com/jaz303/tipsy/blob/master/src/javascripts/jquery.tipsy.js
IMHO the problem is using the combination of jQuery.each()
and Tipsy option live:true
Update:
The other stuff I want to do before calling .tipsy()
is checking for some optional configuration.
For example: <a href="#" title="This is a tooltip" class="tipsyfy delayed">Help</a>"
In this example I will add the following option to Tipsy: delayIn:1000
If there is no delayed
class associated to the element this parameter will be delayIn:0
.
Using the same logic, I want to specify the following classes as well: show-top, show-left, show-right, show-bottom
for the Tipsy option called gravity
.
Example: <a href="#" title="This is a tooltip" class="tipsyfy delayed show-left">Help</a>"
The full code:
$(".tipsyfy").each(function () {
var a = "s",
b = 0;
if ($(this).hasClass("show-left")) a = "w";
else if ($(this).hasClass("show-down")) a = "n";
else if ($(this).hasClass("show-right")) a = "e";
if ($(this).hasClass("delayed") && $(this).attr("data-delayIn") != null) b = $(this).attr("data-delayIn");
$(this).tipsy({
gravity: a,
fade: true,
live: true,
delayIn: b
})
})
And here is a full jsFiddle demo with all the stuffs I want to do: http://jsfiddle.net/xmLBG/1/
Answer by mgibsonbr
If you use jQuery 1.7.1 instead of 1.6.4 it will work. Maybe that live feature is relying on something buggy with the older versions, or some not-yet-implemented feature.
Update: from what I understood, you want the tipsy
plugin to be called to every element with the .tipsyfy
class, present now or added in the future. You don’t want to (or can’t) call it explicitly before insertion. You’re trying to accomplish that using the live
option of the plugin. Is that right?
If that’s the case I can offer a workaround. I tried to use on
(since jQuery’s live
is deprecated) to bind some code to the load event, but it didn’t work, so I bound it to mouseenter and checked whether or not the plugin was already built for that element. If not, it builds it and re-triggers the event.
$(document).on("mouseenter", ".tipsyfy", function(e) {
if ( !$(this).data("tipsy") ) {
e.preventDefault();
var a = "s",
b = 0;
if ($(this).hasClass("show-left")) a = "e";
else if ($(this).hasClass("show-down")) a = "n";
else if ($(this).hasClass("show-right")) a = "w";
if ($(this).hasClass("delayed") && $(this).attr("data-delayIn") != null) b = $(this).attr("data-delayIn");
$(this).tipsy({
gravity: a,
fade: true,
live: true,
delayIn: b
}).trigger("mouseenter");
return false;
}
});
Live example at jsFiddle.
For a small optimization, if the sole purpose of the .tispsyfy
class is to instruct the plugin creation, and you don’t need it afterwards, you can remove it prior to re-triggering the mouseenter. This way the checking code won’t be called over and over again:
$(this).tipsy({...}).removeClass("tipsyfy").trigger("mouseenter");
Answer by Starx
Can’t you do this instead? It is what you are asking.
$(".tipsy1,.tipsy2").tipsy({live:true,fade:true});
$(".tipsy2").each(fucntion() {
//do your stuff
});