I'm putting together some code to essentially replace the contents of a div when I mouseover a specific link. I then added the changer function to cycle through the content replacement automatically. I set flags for mouseover and mouseout and I can actually get the changer function to stop on mouseover but I can't quite figure out how to make it start up again on mouseout. Any advice is appreciated.
var pause=false;
$('.banner-nav a').mouseover(function () {
pause=true;
setFeature(this);
return false;
});
$('.banner-nav a').mouseout(function () {
pause=false;
});
changer(0, 5000);
function setFeature(f) {
var m = $(f).attr('rel');
$('.banner-nav a').not(f).removeClass('active');
$(f).addClass('active');
$('#featureContainer').html($(m).html());
}
function changer(index, interval) {
var buttons = $('.trigger'),
buttons_length = buttons.length;
var button = buttons.eq(index % buttons_length);
setFeature($(button));
setTimeout(function() {
if (!pause) {
changer(++index, interval);
}
}, interval)
}
The issue is that changer is responsible for its own delayed execution, but pausing it stops the scheduled execution. Another problem is that the next scheduled execution (if any) still happens after pausing.
Use setInterval instead of setTimeout. Instead of using a flag, clear the interval to pause and start it again to unpause.
(function() {
var index=0;
function changer() {
var buttons = $('.trigger'),
buttons_length = buttons.length;
var button = buttons.eq(index % buttons_length);
setFeature($(button));
++index;
}
var changerInterval,
period = 5000;
function startChanger() {
if (! changerInterval) {
changerInterval = setInterval(changer, interval);
}
}
function stopChanger() {
clearInterval(changerInterval);
changerInterval = 0;
}
$('.banner-nav a').mouseover(function () {
stopChanger();
setFeature(this);
return false;
});
$('.banner-nav a').mouseout(function () {
startChanger();
});
/* could implement other functions to e.g. change the period */
function setChangerPeriod() {
...
}
window.setChangerPeriod = setChangerPeriod;
...
})
Related
I have created a snippet of code that changes the state from display:block to display:none by using an onClick element. My goal is to delay the change in state, for a few seconds whilst an animation effect occurs.
This snippet of code below is what I am currently using to change the state of the element, but unsure on how to incorporate a delay.
Any advice or suggestions is greatly appreciated.
Thanks,
Ant
function showDiv1(elem) {
var divsToCheck = ["close","Holder"]; // Add to here to check more divs
for (var i = 0; i < divsToCheck.length; i++) {
if (divsToCheck[i] == elem) {
document.getElementById(divsToCheck[i]).style.display = "block";
} else {
document.getElementById(divsToCheck[i]).style.display = "none";
}
}
}
Put the code you want to be delayed inside an anonymous function, like so:
function showDiv1(elem) {
var divsToCheck = ["close","Holder"]; // Add to here to check more divs
for (var i = 0; i < divsToCheck.length; i++) {
if (divsToCheck[i] == elem) {
setTimeout(function() {
document.getElementById(divsToCheck[i]).style.display = "block";
}, 500);
} else {
setTimeout(function() {
document.getElementById(divsToCheck[i]).style.display = "none";
}, 500);
}
}
}
Here, 500 means delaying by 500 ms. You can change this to whatever amount of time (in milliseconds) that you need.
You should call a function in your loop that takes care of the setTimeout and hiding/showing instead of calling the timeout function in a loop. (Won't work because i is no longer available). See here: https://jsbin.com/refodobaca/1/edit?html,css,js,output
function showDiv1(elem) {
var divsToCheck = ["close","Holder"]; // Add to here to check more divs
for (var i = 0; i < divsToCheck.length; i++) {
if (divsToCheck[i] == elem) {
showHideDiv(divsToCheck[i], true);
} else {
showHideDiv(divsToCheck[i], false);
}
}
}
function showHideDiv(elem, bShow) {
var timeoutSeconds = 3;
setTimeout(function() {
document.getElementById(elem).style.display = (bShow ? "block" : "none");
}, timeoutSeconds * 1000);
}
showDiv1('Holder');
Your question is a little unclear because the name of your function is showDiv1 but you explain that you're trying to hide an element, so I've tried to answer in light of this and hopefully it will give you some ideas.
This code displays a couple of divs. If you click on them they turn red and, after a couple of seconds (to represent an animation), they are hidden.
dummyAnim returns a promise. After the animation has run its course (here represented by a two second delay) it is resolved. I've used await to pause code execution in an async function until the animation has resolved.
// Grab the elements and add click handlers to them
const divs = document.querySelectorAll('div');
divs.forEach(div => div.addEventListener('click', hideElement, false));
function dummyAnim() {
// return a promise which resolves (an animation)
// after two seconds
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), 2000);
});
}
async function hideElement() {
this.classList.add('red');
await dummyAnim();
this.classList.add('hidden');
}
div { color: black; display: block }
.hidden { display: none }
.red { color: red }
<div>close</div>
<div>holder</div>
The idea behind this to animate section with mousewheel - keyboard and swipe on enter and on exit. Each section has different animation.
Everything is wrapp inside a global variable. Here is a bigger sample
var siteGlobal = (function(){
init();
var init = function(){
bindEvents();
}
// then i got my function to bind events
var bindEvents = function(){
$(document).on('mousewheel', mouseNav());
$(document).on('keyup', mouseNav());
}
// then i got my function here for capture the event
var mouseNav = function(){
// the code here for capturing direction or keyboard
// and then check next section
}
var nextSection = function(){
// Here we check if there is prev() or next() section
// if there is do the change on the section
}
var switchSection = function(nextsection){
// Get the current section and remove active class
// get the next section - add active class
// get the name of the function with data-name attribute
// trow the animation
var funcEnter = window['section'+ Name + 'Enter'];
}
// Let's pretend section is call Intro
var sectionIntroEnter = function(){
// animation code here
}
var sectionIntroExit = function(){
// animation code here
}
}();
So far so good until calling funcEnter() and nothing happen
I still stuck to call those function...and sorry guys i'm really not a javascript programmer , i'm on learning process and this way it make it easy for me to read so i would love continue using this way of "coding"...Do someone has a clue ? Thanks
Your concatenation is right but it'd be better if you didn't create global functions to do this. Instead, place them inside of your own object and access the functions through there.
var sectionFuncs = {
A: {
enter: function() {
console.log('Entering A');
},
exit: function() {
console.log('Exiting A');
}
},
B: {
enter: function() {
console.log('Entering B');
},
exit: function() {
console.log('Exiting B');
}
}
};
function onClick() {
var section = this.getAttribute('data-section');
var functions = sectionFuncs[section];
functions.enter();
console.log('In between...');
functions.exit();
}
var buttons = document.querySelectorAll('button');
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', onClick);
}
<button data-section="A">A</button>
<button data-section="B">B</button>
You could have an object that holds these functions, keyed by the name:
var enterExitFns = {
intro: {
enter: function () {
// animation code for intro enter
},
exit: function () {
// animation code for intro exit
}
},
details: {
enter: function () {
// animation code for details enter
},
exit: function () {
// animation code for details exit
}
}
};
var name = activeSection.attr('data-name');
enterExitFns[name].enter();
I created this little function that loops through images when you go mouse over:
function THUMB_ROLL(NEXT)
{
LENGTH = ALL_IMAGES.length;
if(!LENGTH) { return false; }
if(!NEXT || NEXT === LENGTH) { NEXT = 0 }
$('#IMAGE_THUMB').css('background-image','url(/<?php echo $ITEM_CODE;?>/'+ALL_IMAGES[NEXT]+')');
setTimeout(function()
{
THUMB_ROLL(NEXT+2)
},800);
}
</script>
I have, onmouseover="THUMB_ROLL();"
But, I cannot seem to find a solution to stop the loop once onmouseout. Any help appreciated!
EDIT
<script>
var timer;
function THUMB_ROLL(NEXT)
{
LENGTH = ALL_IMAGES.length;
if(!LENGTH) { return false; }
if(!NEXT || NEXT === LENGTH) { NEXT = 0 }
$('#IMAGE_THUMB').css('background-image','url(/<?php echo $ITEM_CODE;?>/'+ALL_IMAGES[NEXT]+')');
timer = setTimeout(function()
{
THUMB_ROLL(NEXT+1)
},800);
}
$(document).on('mouseover','#IMAGE_THUMB',function()
{
THUMB_ROLL();
});
$(document).on('mouseout','#IMAGE_THUMB',function()
{
clearTimeout(timer);
});
</script>
Assign your timeout to a variable which store the timerID.
Then have the moueout clear the timeout, which should stop the flow.
var timer;
// mouseover event..
timer = setTimeout(function() {
THUMB_ROLL(NEXT+2)
},800);
// mouseout event
clearTimeout(timer);
Also it is a better idea to separate your concerns and attach the events inside the script tags instead of attaching them inline.
I have a piece of code that hides an element on mouseout.
The code looks like this:
var myMouseOutFunction = function (event) {
setTimeout(function () {
$(".classToHide").hide();
$(".classToShow").show();
}, 200);
};
This produces a result very close to what I want to do. However, I want to wait the time on the timeout (in this case 200 ms) then check to see if my mouse is still "out" of the element. If it is, I want to do .hide() and .show() on the desired elements.
I want to do this because if a user slightly mouses out then quickly mouses back in, I don't want the elements to flicker (meaning: hide then show real quick) when the user just wants to see the element.
Assign the timeout's return value to a variable, then use clearTimeout in the onmouseover event.
Detailing Kolink answer
DEMO: http://jsfiddle.net/EpMQ2/1/
var timer = null;
element.onmouseout = function () {
timer = setTimeout(function () {
$(".classToHide").hide();
$(".classToShow").show();
}, 200);
}
element.onmouseover = function () {
clearTimeout(timer);
}
You should use mouseenter and mouseleave of jquery. mouseenter and mouseleave will get called only once.and use a flag if to check if mouseenter again called.
var isMouseEnter ;
var mouseLeaveFunction = function (event) {
isMouseEnter = false;
setTimeout(function () {
if(isMouseEnter ){ return;}
$(".classToHide").hide();
$(".classToShow").show();
}, 200);
};
var mouseEnterFunction = function(){
isMouseEnter = true;
}
Use a boolean flag:
var mustWait = true;
var myMouseOutFunction = function (event) {
setTimeout(function () {
if(mustWait){
mustWait = false;
}
else{
$(".classToHide").hide();
$(".classToShow").show();
mustWait = true;
}
}, 200);
};
Please take a look at this function:
var msgdiv, i=0;
msgdiv=$("#message");
messages=["Welcome!","Добро пожаловать!"];
function fadeMessages(messages, div){
while(i<messages.length){
div.fadeOut(1000).html('').append(messages[i]).fadeIn(1000);
i=i+1;
}
}
fadeMessages(messages,msgdiv);
What I want to do is, to show one by one elements of array. But, function above shows only last element of array messages.length time. Where I did wrong?
Live example: http://jsfiddle.net/QQy6X/
The while executes much much faster than the fadeOut/fadeIn calls, so you only see the last result. You need to make each animation wait for the previous ones to finish.
I like to solve these problems recursively. Note, it does alter the messages array, but it's not too hard to convert this to use a counter instead (like your original version). Here you go:
var $msgdiv = $('#message'),
messages = ['Xoş gəlmişsiniz!', 'Welcome!', 'Добро пожаловать!'];
function showNext() {
var msg = messages.shift();
if (msg) {
$msgdiv.fadeOut(1000, function () {
$(this).text(msg).fadeIn(1000, showNext);
});
}
}
showNext();
Demo: http://jsfiddle.net/mattball/Exj95/
Here's a version that leaves messages intact:
var $msgdiv = $('#message'),
messages = ['Xoş gəlmişsiniz!', 'Welcome!', 'Добро пожаловать!'],
i = 0;
function showNext() {
if (i < messages.length) {
var msg = messages[i];
$msgdiv.fadeOut(1000, function () {
i++;
$(this).text(msg).fadeIn(1000, showNext);
});
}
}
showNext();
Demo: http://jsfiddle.net/mattball/wALfP/
Your while loop finishes executing before the div has had a chance to fade out. Use an if statement and recursion:
var msgdiv = $("#message");
var i = 0;
var messages = ["Welcome!", "Добро пожаловать!"];
(function fadeMessages() {
if (i in messages) {
msgdiv.fadeOut(1000, function() {
$(this).html('').append(messages[i++]).fadeIn(1000, fadeMessages);
});
}
})();
http://jsfiddle.net/QQy6X/6/
Your while loop finishes very quickly; instead you should wait for the animation to finish before starting the next one. This is easy to do by adding a callback function to fadeIn. I would use this:
+function(){
var $msgdiv = $("#message");
var i = -1;
var messages = ["Xoş gəlmişsiniz!","Welcome!","Добро пожаловать!"];
+function fadeNext(){
$msgdiv.fadeOut(1000, function(){
$msgdiv.text(messages[i = (i + 1) % messages.length]);
$msgdiv.fadeIn(1000, fadeNext);
});
}();
}();
http://jsfiddle.net/Paulpro/QQy6X/7/
In jQuery, you can't intertwine animations and non-animations in the way you are doing and expect them to run in the right order. The animations will go into the animation queue and get sequenced one after another there, but the non-animations will all run immediately. Thus, things won't happen in the right order.
To do something like you want to do, you can use code like this.
messages=["Welcome!","Добро пожаловать!"];
function fadeMessages(msgs, div) {
var i = 0;
function next() {
if (i < msgs.length) {
div.fadeOut(1000, function() {
div.html(msgs[i++]).fadeIn(1000, next);
});
}
}
next();
}
fadeMesssages(messages, div);
This uses the completion functions of both fadeIn() and fadeOut() to carry out the next steps. Here's how it works:
It fades out the div.
In the completion function of the fadeOut, it sets the next message and then starts the fadeIn.
It advances the message counter.
In the completion function from the fadeIn, it calls the function to start the next iteration.
If you want a delay before the fadeOut (to make sure a given message displays for a certain amount of time), you can add that with this .delay(2000) added in the right place:
messages=["Welcome!","Добро пожаловать!"];
function fadeMessages(msgs, div) {
var i = 0;
function next() {
if (i < msgs.length) {
div.delay(2000).fadeOut(1000, function() {
div.html(msgs[i++]).fadeIn(1000, next);
});
}
}
next();
}
fadeMesssages(messages, div);
If you want a delay before the next iteration starts, you can do that like this with a setTimeout:
messages=["Welcome!","Добро пожаловать!"];
function fadeMessages(msgs, div) {
var i = 0;
function next() {
if (i < msgs.length) {
div.fadeOut(1000, function() {
div.html(msgs[i++]).fadeIn(1000, function() {
setTimeout(next, 2000);
});
});
}
}
next();
}
fadeMesssages(messages, div);