How to add a delay to a jQuery fadeout? - javascript

I'm designing a navigation bar for a site, and I'm trying to noodle out how to get the submenu that appears with each tab to stay visible after the cursor leaves the tab. Since it fades out immediately after the cursor leaves, I can't set a function on the submenu. So what I'm trying to do is introduce a setTimeout() to the out side of the .hover in jQuery, without success. Here's the code:
$('.hovernav').hover(
function () {
$(this).css('background-image', $(this).css('background-image').replace("_o.", "_i."));
tabShowSubnav($(this).attr('id'));
},
function () {
$(this).css('background-image', $(this).css('background-image').replace("_i.", "_o."));
setTimeout('tabHideSubnav($(this).attr("id"))','2000');
});
What am I missing about this setup?

function () {
....
setTimeout('tabHideSubnav($(this).attr("id"))','2000');
}
‘this’ in the inner function is set to the obect the timeout was called on, which is window, not the current instance of hovernav.
Best not to use a string with setTimeout; use a function instead. Then you get access to variables in the enclosing scope, which you can use to remember the this value that was passed to the outer function.
function() {
...
var thisid= this.id;
setTimeout(function() {
tabHideSubnav(thisid);
}, 2000);
}
(As a bonus, this stops JavaScript from having to recompile the function from your string every time. Putting code in strings is almost always bogus.)
Note you will probably need some more logic to cancel the hide-subnav if the mouse goes back into the hovernav. Otherwise instead of an annoying menu bar that keeps closing when the mouse leaves, you've got an even more annoying menu bar that keeps closing the menu even whilst you're hovering it, if you mousedout two seconds ago.

Just taking a guess here, but maybe "this" is out of scope when the function gets called.

Have you tried to have it show() on hover, then fadeOut('slow') on mouseout?
http://docs.jquery.com/Effects/fadeOut
Alternatly, you could .animate({opacity: 0}, 3000) or w/e amount would work for you.
One more edit:
you can have .animate({opacity: 1}, 3000) which would simply delay an already visible element for 3 seconds.
Taken from: http://www.learningjquery.com/2007/01/effect-delay-trick
Here is a simple snippet:
JQuery
$(function(){
$("#HeaderMenu").mouseover(function(){
$("#SubMenu").show();
});
$("#HeaderMenu").mouseout(function(){
$("#SubMenu").animate({opacity: 1}, 3000, function(){$(this).hide()});
});

Related

Animation not completing transition on SVG hover animation, when hover out occurs fast

I have made a very simple hover animation for a thumbnail by using a SVG icon. See here. The JS code I used is like so:
var elemRemoveAnim = null;
$('.vedio-thumb').hover(
function(){
$(this).find('.youtube-icon > .youtube-red')[0].classList.add('y-animated' , 'fadeInUp');
$(this).find('.youtube-icon > .youtube-white')[0].classList.add('y-animated' , 'fadeInUp');
},
function(){
removeVedioAnim($(this));
});
function removeVedioAnim(elem) {
elemRemoveAnim = elem;
setTimeout(function(){
elemRemoveAnim.find('.youtube-icon > .youtube-red')[0].classList.remove('y-animated' , 'fadeInUp');
elemRemoveAnim.find('.youtube-icon > .youtube-white')[0].classList.remove('y-animated' , 'fadeInUp');
}, 1000);
}
As you can see, I am trying to remove the animation class, after a delay of 1000ms, that's because iif you hover over and immediately hover out (you'll have to do it really fast), you'll notice that the animation gets stuck, i.e. the white arrow will still only be in half transition. Technically this is happening because the animation class has been removed too soon.
If I add the code in the hover out function, this aggravates the situation even more. Is there a more versatile solution to this problem?
One more problem with the with this solution is that once you hover and then if you hover out and you do it 2-3 times really fast, for the 2-3 time you've hovered the animation will take play only once, simply the setTimeout function will wait 1 second to remove the classes. I wonder if there is a more elegant way to do this.
SEE DEMO
Use "animationend" event to capture the end of fadingInUp motion on the arrow, that runs longer (the white one).
$utube_white.one("animationend webkitAnimationEnd oAnimationEnd",function() {
$utube_red.get(0).classList.remove('y-animated' , 'fadeInUp');
$utube_white.get(0).classList.remove('y-animated' , 'fadeInUp');
isLocked = false;
});
In your example there's no need for a mouseleave function in HOVER event, because you don't do anything particular on it - just remove animation classes without any other motion. This could be done in "Animationend" event in the first "HandlerIn" function.
Instead of a mouseleave function put the empty $.noop to prevent jQuery think that your hover function contains only one argument.
.hover(handlerIn, $.noop) and not .hover( handlerInOut ). You can change it, it's up to you, but in the last case the function will fire on both MouseOn and MouseOut.
Use a flag "isLocked" as well to prevent firing HandlerIn on quick hovers.

How to detect when all animations have stopped?

I'm using this code to stop simultaneous animations on 2 elements:
$('#container').find('*').stop(true, true);
The animation can be stopped by an end user hovering over a button, in which case the animation stops after completion (which is what I want). However, the button hover also initiates another function (removes and reloads the elements), and there's a conflict if that function runs before the animations are complete.
I was thinking that using 'after' or 'complete' with the above code might work, but I can't figure out what the syntax would be.
im not sure what you are trying to achieve, but in order to check whether or not there are running/pending animations on the object using jQuery, you can use .promise().done()
example, somehing of this sort:
var animations_running;
$('#container').promise().done(function() {
animations_running=false;
});
$('#container').on("mouseover",".SomethingInside",function(){
if(animations_running==false){
//...do animations...
animations_running=true;
}
});
you can also add a callback function to your jQuery animations as follows:
$('#container').on("mouseover",".SomethingInside",function(){
if(animations_running==false){
$(this).animate({
left:+=50
},500,function(){
//...this is the callback function...
});
animations_running=true;
}
});

Fade in or fade out based on scroll

$(document).scroll(function () {
var y = $(this).scrollTop();
if (y > 397) {
$('#aboutNav.fixed').fadeIn(500);
} else {
$('#aboutNav.fixed').hide();
}
});
As you can tell, this shows a fixed navigation. The CSS is fine, the positioning is great. However I want the navigation to become visible above 397px which it does fine.
However I want the navigation to fade in when I start scrolling:
.fadeIn(500);
When the user starts stops to look at content or whatever, I want the element to fade out
.delay(3000).fadeOut(350);
I believe this is something that can be done by doing an if statement within the first if statement. However a script to check if the user is scrolling and the working script above seem to collide.
Ideas, anyone?
If I understand you correctly. You want the nav to fade in if its above 397px and only when its scrolling... So this function will do that. If I misunderstood your question please clarify in the comments
$(window).scroll(function() {
clearTimeout($.data(this, 'scrollTimer'));//Lets the timer know were scrolling
//Hide/Show nav based on location
var y = $(this).scrollTop();
if (y > 397) {
$('#aboutNav.fixed').fadeIn(500);
} else {
$('#aboutNav.fixed').hide();
}
//TimeOut function that is only hit if we havent scrolled for 3 Seconds
//In here is where you fade out the nav
$.data(this, 'scrollTimer', setTimeout(function() {
$('#aboutNav.fixed').fadeOut();
console.log("Haven't scrolled in 3s!");
}, 3000));
});
JAN 23 UPDATE based on your comment
You can add this to you $(document).ready() function
$("#elementID").hover(function(){
//show here (mouse over)
$("#elementToShow").show();
},function(){
//Start timeout here, (mouse out)
setTimeout(function() {
$("#elementToHide").hide();
}, 3000);
}
Expanding on what Kierchon's answer a bit:
Since there's no real way to tell when the user is done scrolling (i.e. no event for 'finished scrolling') you'll have to use a event-delaying method called debouncing.
Debouncing is basically setting a timeout to run some code (a function) in the future, and if the event calling the debounced function get called again, you clear and reset the timeout, doing this repeatedly until the event finally stops being called. This method is to prevent events that fire repeatedly (such as scroll and resize) to only execute things after the final event fires and your delayed (debounced) code finally executes.
Here is a nice article on use of debouncing methods in JS.
As long as I understand what you need (which I think I do) - Here's a JSBin with some working code

calling a Jquery function to initiate a hover effect onclick of a href

Ok, sorry if I am misunderstanding, or misinterpreting, anything, but I am fairly new to jQuery and javascript.
I have built a shop in php, and one of the elements is a jQuery cart that is 'required' in all pages so its always on page. The jQuery I include on page to make it work is as follows:
$(document).ready(function(){
$("#cbox").hover(function(){
$(this).stop(true,false)
.animate({right: 0}, 500); },
function(){
$("#cbox").stop(true,false).animate({right: -120}, 500); });
});
Basically the cart sits on the right side of the page, and on hover pops/slides out.
I would like to make it programmatically pop/slide out when the user adds an item to the basket, as a sort of notification of the event. Ideally using onclick.
I have tried calling various parts, but as its a on document ready overall function, I am struggling as to what my onclick should say. Am am not even sure if it will work.
Can anyone give me a point in the right direction please?
$(document).ready(function(){
$("#cbox").hover(function()
{
$(this).stop(true,false)
//.animate({right: 0}, 500); },function()<-- invalid syntax: leave out parentheses and semi-colon:
.animate({right: 0}, 500,function()
{//no need for the selecot here
$(this).stop(true,false).animate({right: -120}, 500);
});
});
$('.storeItems').on('click',function()
{//best use on for AJAX content, for example
$('#cbox').trigger('hover');/
});
});//you were missing this closing
There's one suggestion I'd like to make: the .on('click' handler has a jQuery selector in it. This means that you'll scan the DOM on each click event for that #cbox element. You can make your code more efficient by using a closure here:
$('.storeItems').on('click',(function(cbox)
{
return function()
{//cbox is a reference to the cart element, in memory so no need to scan the dom over and over
cbox.trigger('hover');
};
}($('#cbox'))));//pass the reference here
I know, there's a lot of function's and even more parentheses and brackets. You don't have to use this approach, but just keep this in the back of your mind as you go about learning more JS: you'll start using closures sooner or later, I promise :)
Call the hoverfunction on click of another item is one of many solutions
$(document).ready(function(){
$("#cbox").hover(function(){
$(this).stop(true,false)
.animate({right: 0}, 500); },
function(){
$("#cbox").stop(true,false).animate({right: -120}, 500); });
});
$('.itemClicked').click(function(e){
$('#cbox').trigger('hover');
});
});

Checking for visibility of a toggled element

I have a button which toggles the visibility of a <div> below it and want to modify the text on the button depending on the visibility of said <div>.
Here is a live demo on jsFiddle
If you click on "Saved Data", the first time it works correctly, but the next time you click the text does not change. This in itself is behaviour that I don't understand.
Now, I could use multiple handlers for slideToggle(), however, elsewhere in the code I also set intervals which load data next to "Cookie data:" and "Server data:". I don't want these intervals to do anything if the <div> is not visible so I use something like this:
this.timer_cookiedata = setInterval(function(){
if (!$savedData.is(':visible'))
{
return null;
}
// ..
});
I'm worried these intervals are not going to work properly because of this is(':visible') business. So the question is, why does this happen (else statement is ignored), and what can I do to mitigate this?
Check out the updated fiddle. When you check for visibility right after you call slideToggle, jQuery may not have updated the visibility of the element yet since the animation takes some time to finish. For this exact reason, slideToggle has a callback you can use to perform operations after the animation has finished:
$(function () {
var $savedData = $('#savedData');
$('#btn-savedData')
.click(function () {
var $button = jQuery(this);
//I'm checking the visibility in the callback. Inside the callback,
//I can be sure that the animation has completed and the visibility
//has been updated.
$savedData.slideToggle('fast', function () {
if ($savedData.is(':visible')) {
$button.html('visible');
} else {
$button.html('not visible');
}
});
});
});​

Categories