jQuery setTimeout - not working when using to update data - javascript

I have a list of thumbnails. When I click on a thumbnail, I want the image to load after half a second. Here's my code:
$('ul#thumbs li img').click(function() {
setTimeout(function() {
$('img#image').attr("src", $(this).attr("src").replace("_thumb", ""));
}, 500);
});
When I click on one of the thumbs, nothing happens. If I remove the setTimeout function, and just have the image load immediately, it works fine.
Anybody know why the event wouldn't fire?

this isn't what you think it is. When you use setTimeout, this is no longer a reference to the current element when the function gets executed.
You'll need to make sure you are keeping track of the proper element, like so:
$('ul#thumbs li img').click(function() {
var thumbImg = this;
setTimeout(function() {
$('img#image').attr("src", $(thumbImg).attr("src").replace("_thumb", ""));
}, 500);
});

The problem is the scope of this in the timeout function try this:
$('ul#thumbs li img').click(function() {
var self = $(this);
setTimeout(function() {
$('img#image').attr("src", self.attr("src").replace("_thumb", ""));
}, 500);
});
Or even better this:
$('ul#thumbs li img').click(function() {
var src = $(this).attr("src").replace("_thumb", "");
setTimeout(function() {
$('img#image').attr("src", src);
}, 500);
});

Related

jQuery - mouseenter / mouseleave with timer not functioning

What I am trying to do is only run my code when someone has hovered on an element for 1 second.
Here is the code that I am using:
var timer;
$(".homeLinkWrap").mouseenter(function() {
timer = setTimeout(function(){
$(this).find('.homeLinkNfo').removeClass('flipOutY').addClass('flipInY').css({opacity: '1'});
console.log('in');
}, 1000);
}).mouseleave(function() {
$(this).find('.homeLinkNfo').removeClass('flipInY').addClass('flipOutY');
console.log('out');
clearTimeout(timer);
});
The first part (mouseenter) IS NOT functioning and DOESN'T remove the class and then add the new one. The second one (mouseleave) IS functioning properly and DOES remove the class and add the new one.
I am guessing it is because I am targeting $(this) which is the current element being hovered over and since it is in a timer function jQuery doesn't know which element $(this) is referring to.
What can I do to remedy this?
I think it is because you are calling $(this) inside the setTimeout function. You need to do something like this:
$(".homeLinkWrap").mouseenter(function() {
var $self = $(this);
timer = setTimeout(function(){
$self.find('.homeLinkNfo').removeClass('flipOutY').addClass('flipInY').css({opacity: '1'});
console.log('in');
}, 1000);
});
Inside the setTimeout callback, this no longer refers to the jQuery selection. You should either keep a reference to the selection:
$(".homeLinkWrap").mouseenter(function() {
var $this = $(this);
timer = setTimeout(function(){
$this.find('.homeLinkNfo').removeClass('flipOutY').addClass('flipInY').css({opacity: '1'});
console.log('in');
}, 1000);
})
Or use an arrow function (ES2015)
$(".homeLinkWrap").mouseenter(function() {
timer = setTimeout(() => {
$(this).find('.homeLinkNfo').removeClass('flipOutY').addClass('flipInY').css({opacity: '1'});
console.log('in');
}, 1000);
})
The problem here is that the this inside the callback function that you're passing to setTimeout doesn't reference to the same point that the this outside the callback does.
There are some ways of solving your problem, I'll suggest you to use Function.prototype.bind to bind your callback function to the same this you have outside:
var timer;
$(".homeLinkWrap").mouseenter(function() {
timer = setTimeout((function() {
$(this).find('.homeLinkNfo').removeClass('flipOutY').addClass('flipInY').css({ opacity: '1' });
}).bind(this), 1000);
}).mouseleave(function() {
$(this).find('.homeLinkNfo').removeClass('flipInY').addClass('flipOutY');
clearTimeout(timer);
});

faking a Gif with javascript/jquery

I have a function that hides and shows divs on scroll based on pageY position, but I also need the ability to have it automatically hide and show divs in order(only the ones with children), sort of like a fake animated Gif, looping forever.
I tried this:
function autoPlay() {
$('.conP').each(function(){
if ($(this).children().length > 0) {
setInterval(function(){
$(this).show().delay('100').hide();
},300);
}
});
}
which is not returning any errors, but it's not hiding or showing any of the divs with class="conP".
Any suggestions as to what I'm doing wrong/how I could improve this?
try this -
function autoPlay() {
$('.conP').each(function(){
if ($(this).children().length > 0) {
var $that = $(this);
setInterval(function(){
$that.show().delay('100').hide();
},300);
}
});
}
You have an incorrect reference to this in your setInterval closure. Refer to "How this works" in JavaScript Garden.
In your case you should save the reference to this in a variable:
$('.conP').each(function() {
var $element = $(this);
setInterval(function () {
$(element).show().delay('100').hide();
}, 300);
});
Or, better use the first argument passed to each, which is equal to $(this) in this case.
Not sure it's a great idea to run intervals inside loops, but I'm guessing the issue is scope inside the interval function :
function autoPlay() {
$('.conP').each(function(i, elem){
if ( $(elem).children().length ) {
setInterval(function(){
$(elem).show().delay(100).hide();
},300);
}
});
}
I really appreciate all the help guys, I seem to have figured out the animation part:
setInterval( function() {
autoPlay();
},120);
function autoPlay() {
var backImg = $('#outterLax div:first');
backImg.hide();
backImg.remove();
$('#outterLax').append(backImg);
backImg.show();
}
By hiding whichever div is first, and removing it from-then appending it back into-the containing div, and showing the new first div, it animates quite nicely!

How to add a wait time before hover function is executed

I am working on a nested menu, and when my mouse move over a option, a sublist will show up.
Here is my hover function:
$( ".sublist" ).parent().hover( function () {
$(this).toggleClass("li_hover",300); //use to change the background color
$(this).find(".sublist").toggle("slide", {}, 500); //sub list show / hide
});
Now, I want add a short period before the sublist shows up to prevent the crazy mouse moving from user. Does somebody have a good suggestion on this?
Update:
Thanks for you guys, I did a little bit change on my program, recently it looks like this:
function doSomething_hover (ele) {
ele.toggleClass("li_hover",300);
ele.find(".sublist").toggle("slide", {}, 500);
}
$(function () {
$( ".sublist" ).parent().hover( function () {
setTimeout(doSomething_hover($(this)), 3000);
});
}):
This is weird that setTimeout will not delay anything. but if I change the function call to doSomething_hover (without "()"), the function will delay good. but i can not pass any jquery element to the function, so it still not works, could somebody tell me that how to make doSomething_hover($(this)) work in setTimeout ?
Update 2:
Got the setTimeout work, but it seems not what I want:
What I exactly want is nothing will happen, if the mouse hover on a option less than 0.5sec.
Anyway, here is the code I make setTimeout work:
function doSomething_hover (ele) {
ele.toggleClass("li_hover",300);
ele.find(".sublist").toggle("slide", {}, 500);
}
$(function () {
$( ".sublist" ).parent().hover( function () {
var e = $(this);
setTimeout(function () { doSomething_hover(e); }, 1000);
});
}):
Final Update:
I got this work by using clearTimeout when I move the mouse out.
so the code should be:
$( ".sublist" ).parent().mouseover( function () {
var e = $(this);
this.timer = setTimeout(function () { doSomething_hover(e); }, 500);
});
$( ".sublist" ).parent().mouseout ( function () {
if(this.timer){
clearTimeout(this.timer);
}
if($(this).hasClass("li_hover")){
$(this).toggleClass("li_hover");
}
$(this).find(".sublist").hide("slide", {}, 500);
});
This is the part in the $(document).ready(). Other code will be same as above.
真. Final Update:
So, mouseover and mouseout will lead to a bug sometime, since when I move the mouse to the sublist, the parents' mouseover event will be fire, and hide the sublist.
Problem could be solved by using hover function:
$( ".sublist" ).parent().hover(
function () {
var e = $(this);
this.timer = setTimeout(function () { doSomething_hover(e); }, 500);
},
function () {
if(this.timer){
clearTimeout(this.timer);
}
$(this).find(".sublist").hide("slide", {}, 500);
if($(this).hasClass("li_hover")){
$(this).toggleClass("li_hover",300);
}
}
);
Thanks all
Try this please:
Code
setInterval(doSomthing_hover, 1000);
function doSomthing_hover() {
$(".sublist").parent().hover(function() {
$(this).toggleClass("li_hover", 300); //use to change the background color
$(this).find(".sublist").toggle("slide", {}, 500); //sub list show / hide
});
}​
SetTime vs setInterval
At a fundamental level it's important to understand how JavaScript timers work. Often times they behave unintuitively because of the single thread which they are in. Let's start by examining the three functions to which we have access that can construct and manipulate timers.
var id = setTimeout(fn, delay); - Initiates a single timer which will call the specified function after the delay. The function returns a unique ID with which the timer can be canceled at a later time.
var id = setInterval(fn, delay); - Similar to setTimeout but continually calls the function (with a delay every time) until it is canceled.
clearInterval(id);, clearTimeout(id); - Accepts a timer ID (returned by either of the aforementioned functions) and stops the timer callback from occurring.
In order to understand how the timers work internally there's one important concept that needs to be explored: timer delay is not guaranteed. Since all JavaScript in a browser executes on a single thread asynchronous events (such as mouse clicks and timers) are only run when there's been an opening in the execution.
Further read this: http://ejohn.org/blog/how-javascript-timers-work/
timeout = setTimeout('timeout_trigger()', 3000);
clearTimeout(timeout);
jQuery(document).ready(function () {
//hide a div after 3 seconds
setTimeout( "jQuery('#div').hide();",3000 );
});
refer link
function hover () {
$( ".sublist" ).parent().hover( function () {
$(this).toggleClass("li_hover",300); //use to change the background color
$(this).find(".sublist").toggle("slide", {}, 500); //sub list show / hide
});
}
setTimeout( hover,3000 );
....
You could use .setTimeout
$(".sublist").parent().hover(function() {
setTimeout(function() {
$(this).toggleClass("li_hover", 300); //use to change the background color
$(this).find(".sublist").toggle("slide", {}, 500); //sub list show / hide
}, 1000);
});​

Prevent Double Animation in jQuery

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);
});
});
}
});

Issues with clearTimeout

I am trying to build a simple navigation with sub-navigation drop-downs. The desired functionality is for the drop-down to hide itself after a certain amount of seconds if it has not been entered by the mouse. Though if it is currently hovered, I would like to clearTimeout so that it does not hide while the mouse is inside of it.
function hideNav() {
$('.subnav').hover(function(){
clearTimeout(t);
}, function() {
$(this).hide();
});
}
$('#nav li').mouseover(function() {
t = setTimeout(function() { $('.active').hide()}, 4000);
//var liTarget = $(this).attr('id');
$('.active').hide();
$('.subnav', this).show().addClass('active');
navTimer;
hideNav();
});
What am I missing? Am I passing the handle wrong?
You should also clear the timeout in mouseover, before setting the new timeout.
Otherwise a timeout started before will still be active, but no longer accessible via the t-variable.
you can make the timer variable global.
function hideNav() {
$('.subnav').hover(function(){
clearTimeout(window.t);
}
}
$('#nav li').mouseover(function() {
window.t = setTimeout(function() { $('.active').hide()}, 4000);
});
Try doing it the recommended way (JS statement as a string):
t = setTimeout("$('.active').hide()", 4000);

Categories