I need to show a tooltip when a user hovers over a specific tag on my page. However, I want to do it only if the tag was hovered for at least a second. I tried the code below, but - obviously - setTimeout() will trigger after a second every time, even if the cursor is "long gone".
Is there an easy way in jQuery to achieve this? Not really interested in any plugin-solution.
Fiddle
HTML
<div class="tag-tooltip" id="tooltip-1">Followers: 34</div>
<div class="tag js-tag" data-id="1">Star Wars (hover over me!)</div>
jQuery
$(document).on('mouseenter', '.js-tag', function() {
var $this = $(this);
setTimeout(function() {
$('#tooltip-' + $this.data('id')).show();
}, 2000);
});
$(document).on('mouseleave', '.js-tag', function() {
$('#tooltip-' + $this.data('id')).hide();
});
UPDATE ON SOLUTION
Many good suggestions below, many ways to achieve same thing. I find clearTimeout() solution the cleanest, though. Thanks to everyone who contributed:)
You were almost there, here you go:
http://jsfiddle.net/j21wjtwh/4/
var hoverTimer;
$(document).on('mouseenter', '.js-tag', function() {
var $this = $(this);
hoverTimer = setTimeout(function() {
$('#tooltip-' + $this.data('id')).show();
}, 1000);
});
$(document).on('mouseleave', '.js-tag', function() {
clearTimeout(hoverTimer);
$('#tooltip-' + $(this).data('id')).hide();
});
Use a flag. Set it to false on mouseleave. In mouseenter check if variable is set.
var show = false; // Define var
// ^^^^^^^^^^^^^
$(document).on('mouseenter', '.js-tag', function () {
show = true; // Set to `true`
var $this = $(this);
setTimeout(function () {
if (show) { // Check if true
$('#tooltip-' + $this.data('id')).show();
}
}, 1000);
});
$(document).on('mouseleave', '.js-tag', function () {
$('#tooltip-' + $(this).data('id')).hide();
show = false; // Unset
});
Demo: http://jsfiddle.net/tusharj/j21wjtwh/2/
Here is a Fiddle
Here is a Code
$(document).on('mouseenter', '.js-tag', function() {
var $this = $(this);
setTimeout(function() {
if($('.js-tag').is(":hover"))
{
$('#tooltip-' + $this.data('id')).show();
}
}, 1000);
});
$(document).on('mouseleave', '.js-tag', function() {
$('#tooltip-' + $(this).data('id')).hide();
});
But there is one small bug here, try to hover/unhover fast, and you will see it
EDIT
As for me THIS answer much better. It doesn't contains my bug
Just keep track of whether or not you are currently hovering with a variable.
Set the hovering variable to true on mouse enter, and false on mouseleave.
Then in your setTimeout event, check if you are currently hovering.
Updated Fiddle
var hovering = false;
$('.js-tag').mouseenter(function () {
var $this = $(this);
hovering = true;
setTimeout(function () {
if (hovering) {
$('#tooltip-' + $this.data('id')).show();
}
}, 1000);
});
$('.js-tag').mouseleave(function () {
hovering = false;
$('#tooltip-' + $(this).data('id')).hide();
});
You can store timer handle in variable and clear it using clearTimeout on mouseleave.
Here is jsfiddle for it.
http://jsfiddle.net/Lz9snp9t/3/
Try this:
$('.js-tag').on('mouseover', function() {
var $this = $(this);
if(!$this.data('timeout')) {
$this.data('timeout', setTimeout(function() {
$('#tooltip-' + $this.data('id')).show();
}, 2000);
}
});
$('.js-tag').on('mouseout', function() {
var $this = $(this);
if($this.data('timeout')) {
clearTimeout($this.data('timeout'));
}
$('#tooltip-' + $this.data('id')).hide();
});
Related
I have content that is dynamically loaded. This content needs to be invoked in the following way due to it's dynamic nature.
This works perfectly if no setTimeout is used. Is there a way of setting a timeout of 0.25 seconds in this instance?
Fiddle https://jsfiddle.net/vuezt9dh/
Works
$(".wrapper").on({
mouseenter: function() {
$(this).find('.show-me').slideDown(150);
},
mouseleave: function() {
$(this).find('.show-me').slideUp(0);
}
}, '.main-page');
Doesn't work
$(".wrapper").on({
mouseenter: function() {
var $this = $(this);
setTimeout(function() {
$this.find('.show-me').slideDown(150);
}, 250);
},
mouseleave: function() {
$(this).find('.show-me').slideUp(0);
}
}, '.main-page');
Your targeting is incorrect, i'm suprised this works at all (didn't in my tests)
Demo https://jsfiddle.net/vuezt9dh/2/
Should be:
$(".main-page").on({
mouseenter: function() {
var $this = $(this);
setTimeout(function() {
$this.find('.show-me').slideDown(150);
}, 550);
},
mouseleave: function() {
$(this).find('.show-me').slideUp(0);
}
}, '.wrapper');
Your wrapper and main-page were the wrong way around.
As it stands the remove function doesn't work. Any suggestions?
var toggle = new function() {
$(document).on('click', 'img', function () {
$(this).parent().toggle('slide');
})
}
var remove = new function() {
$(document).on('click', 'img',
setTimeout(function () {
$(this).parent().remove();
}, 1000);
)
}
The function your are looking for is .queue(). It will execute a provided callback after the previous animation has finished:
$(document).on('click', 'img', function() {
var $entry = $(this).parent();
$entry.toggle('slide').queue(function(next) {
$entry.remove();
next();
});
});
Working example: http://jsfiddle.net/rbBgS/
I have a script where I disable a button after it was clicked, for like 5 seconds, and then enable it again.
$(document).on('click', 'button', function () {
var htmls = $(this).html();
$(this).prop("disabled", true);
setTimeout(function () {
$(this).prop("disabled", false);
$(this).html(htmls);
}, 5000);
$(this).html('<img src="<?=CDN(' / icons / loading / loading5.gif ')?>" />');
});
Somehow the setTimeout won't end, so the button won't be enabled again. I don't get any error messages.
Save $(this) into variable before setTimeout call, since this keyword inside setTimeout handler refers to window object:
$(document).on("click", "button", function() {
var $this = $(this),
htmls = $this.html();
$this.prop("disabled", true)
.html('<img src="..." />');
setTimeout(function() {
$this.prop("disabled", false)
.html(htmls);
}, 5000);
});
Here does not refer to the DOM element.Try to put into another temarory variable.Because it is outside to setTimeOut
var $this = $(this),
htmls = $this.html();
$this.prop("disabled", true);
setTimeout(function() {
$this.prop("disabled", false).html(htmls);
}, 5000);
How can I stop this function from happening twice when a user clicks too fast?
$(document).ready(function() {
$(".jTscroller a").click(function(event) {
event.preventDefault();
var target = $(this).attr("href");
$("#photo").fadeTo("fast", 0, function() {
$("#photo").attr("src",target);
$("#photo").load(function() {
$("#photo").fadeTo("fast", 1);
});
});
});
});
The issue I'm having is that if a user clicks too fast the element won't fade back in, it just stays hidden.
The issue wasn't what I thought it was. When I was clicking on the same thumbnail it would try to load in the same image and stick loading forever. The .stop() answer does fix double animation so I'm accepting that answer, but my solution was to check if the last clicked item was the currently displayed item. New script:
$(document).ready(function() {
$(".jTscroller a").click(function(event) {
event.preventDefault();
var last = $("#photo").attr("src");
var target = $(this).attr("href");
if (last != target) {
$("#photo").stop().fadeTo("fast", 0, function() {
$("#photo").attr("src",target);
$("#photo").load(function() {
$("#photo").fadeTo("fast", 1);
});
});
};
});
});
Well you use the correct word in your descripton. Use stop()
$("#photo").stop().fadeTo("fast", 0, function() {
You may use a setTimeout function to make a delay between click grabs. I mean, a second click will be processed only after sometime, after the first click. It sets an interval between clicks.
$(document).ready(function() {
var loaded = true;
$(".jTscroller a").click(function(event) {
if(!loaded) return;
loaded = false;
event.preventDefault();
var target = $(this).attr("href");
$("#photo").fadeTo("fast", 0, function() {
$("#photo").attr("src",target);
$("#photo").load(function() {
$("#photo").fadeTo("fast", 1);
loaded = true;
});
});
});
});
Keep track of its state
I believe what you are looking for is .stop()
http://api.jquery.com/stop/
$("#photo").stop(false, false).fadeTo()
I would prevent it like this:
var photo = $("#photo");
if (0 == photo.queue("fx").length) {
foto.fadeTo();
}
I differs from stop as it will only fire when all animations on this element are done. Also storing the element in a variable will save you some time, because the selector has to grab the element only once.
Use on() and off() :
$(document).ready(function() {
$(".jTscroller a").on('click', changeImage);
function changeImage(e) {
e.preventDefault();
$(e.target).off('click');
$("#photo").fadeOut("fast", function() {
this.src = e.target.href;
this.onload = function() {
$(this).fadeIn("fast");
$(e.target).on('click', changeImage);
});
});
}
});
Target: Object user will hover over to bring up secondary DOM
Tooltip: Fixed DOM object positioned about 10-15px below target
I have made a jquery "tooltip" plugin. This plugin allows users to hover over a DOM object, and will show the "tooltip". I want users to be able to move their mouse from the target to the tooltip without it disappearing the second their mouse leaves the target.
I have tried this:
var hoverTimeout;
data.target.hover(function(){
$this.tooltip('show');
}, function(){
hoverTimeout = setTimeout(function(){
$this.tooltip('hide');
console.log('hey');
}, 1000);
});
data.tooltip.hover(function(){
data.tooltip('show');
clearTimeout(hoverTimeout);
}, function(){
data.tooltip('hide');
});
However, this seems to stop the Tooltip from hiding. The reason I'd like to do this, is so forms can be used, text can be copied, etc., in the tooltip.
I'm hoping something like a setTimeout and clearTimeout will work as I don't want to use hoverintent plugin.
Thank you so much in advance!
You should use the timer both ways:
var hoverTimeout;
data.target.hover(function()
{
hoverTimeout && clearTimeout(hoverTimeout);
$(this).tooltip('show');
},
function()
{
var $this = $(this);
hoverTimeout = setTimeout(function(){
$this.tooltip('hide');
}, 1000);
});
data.tooltip.hover(function()
{
hoverTimeout && clearTimeout(hoverTimeout);
},
function()
{
var $this = $(this);
hoverTimeout = setTimeout(function(){
$this.tooltip('hide');
}, 1000);
});
You should probably combine the two, since you're anyhow doing the exact same thing on both of them:
var hoverTimeout;
data.target.add( data.tooltip ).hover(function()
{
hoverTimeout && clearTimeout(hoverTimeout);
$(this).tooltip('show');
},
function()
{
var $this = $(this);
hoverTimeout = setTimeout(function(){
$this.tooltip('hide');
}, 1000);
});
var hoverTimeout;
data.target.hover(function()
{
$this.tooltip('show');
clearTimeout(hoverTimeout);
}, function()
{
hoverTimeout = setTimeout(function(){
$this.tooltip('hide');
}, settings.delay);
});
data.tooltip.hover(function()
{
clearTimeout(hoverTimeout);
}, function()
{
hoverTimeout = setTimeout(function(){
$this.tooltip('hide');
}, settings.delay);
});