jquery .hover() with else if statement - javascript

I want to put a little delay for onmouseout event for a group of sub items in a drop down menu. But I don't want to use css transitions.
I set it with .hover() and setTimeout method but I wanted to put it only for a specific elements in menu - in this case just for sub items so I used if else statement for them. I have no idea why this if else statement does't work.
Here is my javascript code:
var selectors =
{
element: '.main-menu li:has(ul)'
}
var opacityWorkaround = function ($element, value) {
$element.css('opacity', value);
};
var getAnimationValues = function (visible) {
var result = {
visibility: visible
};
result.opacity = visible === 'visible' ? 1 : 0;
};
var mouseActionHandler = function ($element, visible, opacityValue) {
$element
.stop()
.css("visibility", 'visible')
.animate(getAnimationValues(visible),
3000,
function () {
$(this).css("visibility", visible);
opacityWorkaround($(this), opacityValue);
});
};
var onMouseIn = function () {
var $submenu = $(this).children("ul:first");
if ($submenu) {
mouseActionHandler($submenu, 'visible', 1);
}
};
var onMouseOut = function () {
var $submenu = $(this).children("ul:first");
var $global = $('.global').children('ul');
if ($submenu) {
mouseActionHandler($submenu, 'hidden', 0);
} else if ($global) {
setTimeout(function() {
mouseActionHandler($global, 'hidden', 0);
},1500);
}
};
$(selectors.element).hover(onMouseIn, onMouseOut);
I put 1500ms delay and the $global variable is referring to sub items in menu that I want to make disapear with that delay. I wanted to achieve this when user move mouse cursor out of 'some items >' tab.
Here is my fiddle example.
http://jsfiddle.net/PNz9F/1/
Thanks in advance for any help!

In the example you have in your question $submenu always has a value so the else if statement is never run. You can check for a class instead.
var timeout;
var $submenu = $(this).children("ul:first");
var $global = $('.global').children('ul');
if ($(this).hasClass('menu-item')) {
mouseActionHandler($submenu, 'hidden', 0);
mouseActionHandler($global, 'hidden', 0);
clearTimeout(timeout);
} else if ($(this).hasClass('global')) {
timeout = setTimeout(function() {
mouseActionHandler($global, 'hidden', 0);
},1500);
}

you should be able to just use the :hover selector in your code to check whether the user is hovering over the element or not and run code accordingly

Related

Timeout on mouse enter and leave

I have an unordered list, which changes position when hovering each child element. If I don't put a timeout on mouseover it jumps quickly through the list due to the position changing. What I've noticed is when hovering one li then jumping to the next li, the timeout doesn't finish. I have to leave the li element, wait then re-hover for the timeout to cancel.
I want to be able to hover each li element to update the ul position, but with a timeout so it's not constantly jumping through the list.
I'm open to other suggestions, if this isn't the best way around resolving this.
var time, allow = true;
$("ul").children("li").each(function(index) {
$(this).on('mouseover', function() {
if(allow == true) {
var i = index + 1;
var calc = $('ul').height() / $('ul').children("li").length * i;
$("ul").css('transform', 'translate(-50%, -'+ calc +'px)');
allow = false;
}
}).mouseout(function () {
time = setTimeout(function () {
allow = true;
}, 1000);
});
});
Update: When leaving the current element then hovering the next element the 'allow' isn't finishing the mouseout delay.
var time, allow = true;
$("ul").children("li").each(function(index) {
$(this).find('a').mouseover(function() {
if(allow == true) {
allow = false;
var i = index + 1;
var calc = $('ul').height() / $('ul').children("li").length * i;
$("ul").css('transform', 'translate(-50%, -'+ calc +'px)');
}
});
$(this).mouseout(function () {
time = setTimeout(function () {
allow = true;
}, 1000);
});
});
.bind() is deprecated, so if you dont have to for compatibility reasons, use .on() instead.
Nevertheless what you do is calling .mouseout() on the return value of bind(). There is no documented return value
for bind or on, so you should probably make a separate call like so and while your at it just use the shorthands mouseover() and mouseout() both times:
$("ul").children("li").each(function(index) {
$(this).mouseover(function() {
if(allow == true) {
// do stuff
allow = false;
}
})
$(this).mouseout(function () {
time = setTimeout(function () {
allow = true;
}, 1000);
});
});

How to pause slideshow when hovering

How do I add a pause effect when I hover over an image in a jQuery slideshow?
$(document).ready(function () {
slideShow();
});
function slideShow() {
var showing = $('#slideshow .show');
var next = showing.next().length ? showing.next() : showing.parent().children(':first');
var timer;
showing.fadeOut(500, function () {
next.fadeIn(200).addClass('show');
}).removeClass('show');
setTimeout(slideShow, 3000);
}
var hovering = false; //default is not hovering
$("#slideshow").hover(function () { //*replace body with your element
hovering = true; //when hovered, hovering is true
}, function () {
hovering = false; //when un-hovered, hovering is false
slideShow(); //start the process again
});
function slideShow() {
if(!hovering) { //if not hovering, proceed
/* Your code here*/
nextSlide();
setTimeout(slideShow, 1000);
}
}
function nextSlide(){
var showing = $('#slideshow .show');
var next = showing.next().length ? showing.next() : showing.parent().children(':first');
var timer;
showing.fadeOut(500, function () {
next.fadeIn(200).addClass('show');
}).removeClass('show');
}
Demo: http://jsfiddle.net/DerekL/mqEbZ/
Use .delay() that will help.
Description: Set a timer to delay execution of subsequent items in the queue.
I think you need two functions for that ... slideShow() and other one say pauseSlideshow()... now call the slideshow() on mouseout event and on mouseenter call pauseSlideShow()
your code should be something like this
$(document).ready(function(){
$('.slider').mouseout( slideShow());
$('.slider').mouseenter( pauseSlideShow());
});
function slideShow() {
var showing = $('#slideshow .show');
var next = showing.next().length ? showing.next() : showing.parent().children(':first');
var timer;
showing.fadeOut(500, function() { next.fadeIn(200).addClass('show'); }).removeClass('show');
timeOut = setTimeout(slideShow, 3000);
}
function PauseSlideShow() {
window.clearTimeout(timeOut);
}
TRY IT
Working off of Derek's answer, an alternative to hover would be to use mouseenter and mouseleave.
See the working slideshow Jsfiddle: Demo: http://jsfiddle.net/highwayoflife/6kDG7/
var hovering = false;
var slideshow = $("#slideshow");
slideshow.mouseenter(function() {
hovering = true;
}).mouseleave(function() {
hovering = false;
slideShow();
});
function slideShow() {
if (!hovering) {
# Some browsers don't interpret "display:block" as being visible
# If no images are deemed visible, choose the first...
var currentImg = (slideshow.children("img:visible").length) ? slideshow.children("img:visible") : slideshow.children("img:first");
var nextImg = (currentImg.next().length) ? currentImg.next() : slideshow.children("img:first");
currentImg.fadeOut(500, function() {
nextImg.fadeIn(500, function() {
setTimeout(slideShow, 2000);
});
});
}
}
$(document).ready(function() {
slideShow();
});

does jQuery stop() work on custom functions?

There are three images that I have made a tooltip for each.
I wanted to show tooltips within timed intervals say for 2 seconds first tooltip shows and for the second interval the 2nd tooltips fades in and so on.
for example it can be done with this function
function cycle(id) {
var nextId = (id == "block1") ? "block2": "block1";
$("#" + id)
.delay(shortIntervalTime)
.fadeIn(500)
.delay(longIntervalTime)
.fadeOut(500, function() {cycle(nextId)});
}
now what i want is to stop the cycle function when moseover action occurs on each of the images and show the corresponding tooltip. And again when the mouse went away again the cycle function fires.
If I understand everthing correctly, than try this code. Tt stops the proccess if you hover the image and continues if you leave the image. The stop() function will work on custom functions if you implement them like the fadeOut(), slideIn(), ... functions of jquery.
$('#' + id)
.fadeIn(500, function () {
var img = $(this).find('img'),
self = $(this),
fadeOut = true;
img.hover(function () {
fadeOut = false;
},
function () {
window.setTimeout(function () {
self.fadeOut(500);
}, 2000);
}
);
window.setTimeout(function () {
if (fadeOut === false) {
return;
}
self.fadeOut(500);
}, 2000);
});​

Trying to get my slideshow plugin to infinitely loop (by going back to the first state)

I wrote a slideshow plugin, but for some reason maybe because I've been working on it all day, I can't figure out exactly how to get it to go back to state one, once it's reached the very last state when it's on auto mode.
I'm thinking it's an architectual issue at this point, because basically I'm attaching the amount to scroll left to (negatively) for each panel (a panel contains 4 images which is what is currently shown to the user). The first tab should get: 0, the second 680, the third, 1360, etc. This is just done by calculating the width of the 4 images plus the padding.
I have it on a setTimeout(function(){}) currently to automatically move it which works pretty well (unless you also click tabs, but that's another issue). I just want to make it so when it's at the last state (numTabs - 1), to animate and move its state back to the first one.
Code:
(function($) {
var methods = {
init: function(options) {
var settings = $.extend({
'speed': '1000',
'interval': '1000',
'auto': 'on'
}, options);
return this.each(function() {
var $wrapper = $(this);
var $sliderContainer = $wrapper.find('.js-slider-container');
$sliderContainer.hide().fadeIn();
var $tabs = $wrapper.find('.js-slider-tabs li a');
var numTabs = $tabs.size();
var innerWidth = $wrapper.find('.js-slider-container').width();
var $elements = $wrapper.find('.js-slider-container a');
var $firstElement = $elements.first();
var containerHeight = $firstElement.height();
$sliderContainer.height(containerHeight);
// Loop through each list element in `.js-slider-tabs` and add the
// distance to move for each "panel". A panel in this example is 4 images
$tabs.each(function(i) {
// Set amount to scroll for each tab
if (i === 1) {
$(this).attr('data-to-move', innerWidth + 20); // 20 is the padding between elements
} else {
$(this).attr('data-to-move', innerWidth * (i) + (i * 20));
}
});
// If they hovered on the panel, add paused to the data attribute
$('.js-slider-container').hover(function() {
$sliderContainer.attr('data-paused', true);
}, function() {
$sliderContainer.attr('data-paused', false);
});
// Start the auto slide
if (settings.auto === 'on') {
methods.auto($tabs, settings, $sliderContainer);
}
$tabs.click(function() {
var $tab = $(this);
var $panelNum = $(this).attr('data-slider-panel');
var $amountToMove = $(this).attr('data-to-move');
// Remove the active class of the `li` if it contains it
$tabs.each(function() {
var $tab = $(this);
if ($tab.parent().hasClass('active')) {
$tab.parent().removeClass('active');
}
});
// Add active state to current tab
$tab.parent().addClass('active');
// Animate to panel position
methods.animate($amountToMove, settings);
return false;
});
});
},
auto: function($tabs, settings, $sliderContainer) {
$tabs.each(function(i) {
var $amountToMove = $(this).attr('data-to-move');
setTimeout(function() {
methods.animate($amountToMove, settings, i, $sliderContainer);
}, i * settings.interval);
});
},
animate: function($amountToMove, settings, i, $sliderContainer) {
// Animate
$('.js-slider-tabs li').eq(i - 1).removeClass('active');
$('.js-slider-tabs li').eq(i).addClass('active');
$('#js-to-move').animate({
'left': -$amountToMove
}, settings.speed, 'linear', function() {});
}
};
$.fn.slider = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
return false;
}
};
})(jQuery);
$(window).ready(function() {
$('.js-slider').slider({
'speed': '10000',
'interval': '10000',
'auto': 'on'
});
});​
The auto and animate methods are where the magic happens. The parameters speed is how fast it's animated and interval is how often, currently set at 10 seconds.
Can anyone help me figure out how to get this to "infinitely loop", if you will?
Here is a JSFiddle
It would probably be better to let go of the .each() and setTimeout() combo and use just setInterval() instead. Using .each() naturally limits your loop to the length of your collection, so it's better to use a looping mechanism that's not, and that you can break at any point you choose.
Besides, you can readily identify the current visible element by just checking for .active, from what I can see.
You'd probably need something like this:
setInterval(function () {
// do this check here.
// it saves you a function call and having to pass in $sliderContainer
if ($sliderContainer.attr('data-paused') === 'true') { return; }
// you really need to just pass in the settings object.
// the current element you can identify (as mentioned),
// and $amountToMove is derivable from that.
methods.animate(settings);
}, i * settings.interval);
// ...
// cache your slider tabs outside of the function
// and just form a closure on that to speed up your manips
var slidertabs = $('.js-slider-tabs');
animate : function (settings) {
// identify the current tab
var current = slidertabs.find('li.active'),
// and then do some magic to determine the next element in the loop
next = current.next().length >= 0 ?
current.next() :
slidertabs.find('li:eq(0)')
;
current.removeClass('active');
next.addClass('active');
// do your stuff
};
The code is not optimized, but I hope you see where I'm getting at here.

Javascript "while hovered" loop

Can anybody help me on this one...I have a button which when is hovered, triggers an action. But I'd like it to repeat it for as long as the button is hovered.
I'd appreciate any solution, be it in jquery or pure javascript - here is how my code looks at this moment (in jquery):
var scrollingposition = 0;
$('#button').hover(function(){
++scrollingposition;
$('#object').css("right", scrollingposition);
});
Now how can i put this into some kind of while loop, so that #object is moving px by px for as #button is hovered, not just when the mouse enters it?
OK... another stab at the answer:
$('myselector').each(function () {
var hovered = false;
var loop = window.setInterval(function () {
if (hovered) {
// ...
}
}, 250);
$(this).hover(
function () {
hovered = true;
},
function () {
hovered = false;
}
);
});
The 250 means the task repeats every quarter of a second. You can decrease this number to make it faster or increase it to make it slower.
Nathan's answer is a good start, but you should also use window.clearInterval when the mouse leaves the element (mouseleave event) to cancel the repeated action which was set up using setInterval(), because this way the "loop" is running only when the mouse pointer enters the element (mouseover event).
Here is a sample code:
function doSomethingRepeatedly(){
// do this repeatedly when hovering the element
}
var intervalId;
$(document).ready(function () {
$('#myelement').hover(function () {
var intervalDelay = 10;
// call doSomethingRepeatedly() function repeatedly with 10ms delay between the function calls
intervalId = setInterval(doSomethingRepeatedly, intervalDelay);
}, function () {
// cancel calling doSomethingRepeatedly() function repeatedly
clearInterval(intervalId);
});
});
I created a sample code on jsFiddle which demonstrates how to scroll the background-image of an element left-to-right and then backwards on hover with the code shown above:
http://jsfiddle.net/Sk8erPeter/HLT3J/15/
If its an animation you can "stop" an animation half way through. So it looks like you're moving something to the left so you could do:
var maxScroll = 9999;
$('#button').hover(
function(){ $('#object').animate({ "right":maxScroll+"px" }, 10000); },
function(){ $('#object').stop(); } );
var buttonHovered = false;
$('#button').hover(function () {
buttonHovered = true;
while (buttonHovered) {
...
}
},
function () {
buttonHovered = false;
});
If you want to do this for multiple objects, it might be better to make it a bit more object oriented than a global variable though.
Edit:
Think the best way of dealing with multiple objects is to put it in an .each() block:
$('myselector').each(function () {
var hovered = false;
$(this).hover(function () {
hovered = true;
while (hovered) {
...
}
},
function () {
hovered = false;
});
});
Edit2:
Or you could do it by adding a class:
$('selector').hover(function () {
$(this).addClass('hovered');
while ($(this).hasClass('hovered')) {
...
}
}, function () {
$(this).removeClass('hovered');
});
var scrollingposition = 0;
$('#button').hover(function(){
var $this = $(this);
var $obj = $("#object");
while ( $this.is(":hover") ) {
scrollingposition += 1;
$obj.css("right", scrollingposition);
}
});

Categories