How to pause and resume jquery interval - javascript

I have made a custom slider with jQuery. For this I have used setInterval function:
timer = setInterval(function() {}, 8000);
But I cannot pause and resume the interval. I have 2 buttons (play, pause) which I want to use for. Lets say I click pause after 3 sec, and then resume it. So it should stay in that slider for 5 more seconds and then go to the next one and continue 8 seconds each. I have seen this kinda slider with mouseover pause, but can't do it by myself. I have tried this:
clearInterval(timer);
But this seems reset the interval, don't pause. Can anyone help :)

I'm not entirely sure that's something native to jQuery, however, you could use a flag to pause it, and check in your setInterval whether to execute.
Edit:
Found something that might be useful to you, the jquery-timer
Alternitively, you can keep track of the id set by setInterval, and clear out out when you'd like to pause. Then you can set it again when you wish to resume:
var id = window.setInterval(<code>); //create
window.clearInterval(id); //pause
id = window.setInterval(<code>); //resume

there are two ways of accomplish this:
Clearing the interval everytime you pause and starting a new interval when you resume it.
Having a flag to tell the function in the interval when it is paused and it should not do anything.
The first solution would work like this:
let intervalId = false;
const intervalLength = 8000; // 8 seconds
function intervalFunction () {
// do stuff.
}
startButton.onclick = function () {
if (intervalId === false) {
intervalId = setInterval(intervalFunction, intervalLength);
}
}
pauseButton.onclick = function () {
if (intervalId !== false) {
clearInterval(intervalId);
intervalId = false;
}
}
// auto start it:
intervalId = setInterval(intervalFunction, intervalLength);
The second solution would work like this:
var isRunning = true;
var interval = setInterval(function() {
if (!isRunning) {
// not running, do nothing
} else {
// it is running, do stuff.
}
}, 8000);
pauseButton.onclick = function () {
isRunning = false;
};
startButton.onclick = function () {
isRunning = true;
};

I am not complete sure, that what you are asking for, is the right thing you are showing us... setInterval basically is pure native javascript and in my opinion not worth using! If you wan't to set your timeouts via jquery try this link: http://jchavannes.com/jquery-timer. You can find usages there...
Now on to your problem... you need a state to check wether the slider has to slide or not... simply set a bool like this...
var timer;
var doSlide = false;
var i = 0;
function Slide(){
timer = setTimeout(function(){
if(doSlide == true){
Slide();
i++; // Same as i = i + 1
console.log('Sliding');
if(i == 3) AbortSlide(); /* Abort on third slide! Dont use this in your logic!*/
} else if(doSlide == false){
console.log('Sliding aborted untill next RunSlide() call!')
clearTimeout(timer);
}
},1000);
}
function AbortSlide(){
doSlide = false;
i = 0; // Resetting the count! Dont use this in your logic!
}
function RunSlide(){
doSlide = true;
Slide();
}
RunSlide();
You could also empty the interval in the abort method:
function AbortSlide(){
doSlide = false;
clearTimeout(timer);
i = 0; // Resetting the count! Dont use this in your logic!
}
Here is a working fiddle i made for you to understand what timers and intervals are for: https://jsfiddle.net/q5qzmv68/7/
Hope this helps! Cheers!

Related

endless while loop after mousemove

I am going crazy here.
I want to show an element on mouse move, and hide it 10 sec after last move of the mouse.
I wrote this:
document.addEventListener("DOMContentLoaded", function(event) {
var time = 0;
document.addEventListener("mousemove", function(event) {
console.log('$');
document.getElementsByClassName("mybar")[0].style.visibility = 'visible';
time = 0;
while (time < 11) {
setTimeout(function() {
time++
}, 1000);
console.log(time, time == 10);
if (time == 10) {
document.getElementsByClassName("mybar")[0].style.visibility = 'hidden';
}
}
});
});
<div class='mybar'>
<h1> TESTING </h1>
</div>
Why does it end up in an endless loop?
Why doesn't it exit on condition? why does the if never gets the 'true' parameter?
Notice : don't run it this way... it will kill your tab.
First, you don't need to wait for DOMContentLoaded to add an event listener to document, since if you did, you couldn't add DOMContentLoaded in the first place.
The infinite loop is because setTimeout doesn't pause the script. It schedules its callback for the time you provide, and irrespective of that time, the callbacks will not run until the current running code in the thread completes, which never happens because you don't increment the time variable.
So the loop never ends, and so the thread is never made available, so your callbacks never can run, so time can never be incremented.
Lastly, starting a setTimeout inside an event handler that shares a local variable and executes very rapidly on an event like mousemove is prone to give unexpected results. For example, in your code, every time the handler runs, it'll reset time to 0, which doesn't seem to be what you'd want.
A solution would be to ditch the loop, schedule the visibility for 10 seconds, and prevent the main part of the code in the handler from running in the meantime by using a boolean variable.
var timer = null;
document.addEventListener("mousemove", function(event) {
var myBar = document.querySelector(".mybar");
if (!myBar) {
return; // there's no mybar element
}
if (timer == null) {
myBar.style.visibility = 'visible';
} else {
clearTimeout(timer); // clear the currently running timer
}
// set to hidden in 10 seconds
timer = setTimeout(function() {
myBar.style.visibility = 'hidden';
timer = null; // clear the timer
}, 10000);
});
I also switched to querySelector instead of getElementsByClassName because it's shorter and cleaner. And I used a variable to make sure the element is found before setting the style.
You need a flag out of the mousemove scope that tells your listener that you've already ran.
if(running) return;
running = true;
In context:
document.addEventListener("DOMContentLoaded", function(event) {
var time = 0;
var running = false;
document.addEventListener("mousemove", function(event) {
console.log('$');
if(running) return;
running = true;
document.getElementsByClassName("mybar")[0].style.visibility = 'visible';
time = 0;
while (time < 11) {
setTimeout(function() {
time++
}, 1000);
console.log(time, time == 10);
if (time == 10) {
document.getElementsByClassName("mybar")[0].style.visibility = 'hidden';
}
}
});
});
Here's a way to do it with regular JavaScript. If your browser isnt ES6 compliant, you can replace the arrow functions with regular function expressions. The example hides the text after 2 seconds instead of 10, just so you can see it work without having to waste 8 extra seconds.
//hide by default
document.getElementById('myBar').style.display = 'none';
var timer = null;
var hideDivTimer = () => {
timer = setTimeout(() => {
document.getElementById('myBar').style.display = 'none';
}, 2000);
};
document.addEventListener('mousemove', () => {
clearTimeout(timer);
document.getElementById('myBar').style.display = 'inline';
hideDivTimer();
});
<body>
<div id='myBar'>
<h1> TESTING </h1>
</div>
</body>

How can I depend on the interval that I just cleared in jquery?

It's a follow up to this question - https://stackoverflow.com/a/33430608/3766930
Basically I have a text area and when user starts typing in sth, the counter starts going down from 3 to 0. when it reaches 0 it gets disabled.
Now I want to add a feature of starting over - when user clicks the link start over, text area goes enabled again and user has 3 seconds (again) to perform the input.
I modified the jquery script:
$('#textArea').on('input propertychange', display30Seconds);
var interval;
function display30Seconds() {
var validTime = 3000;
if (!interval)
interval = setInterval(function () {
$('#counter').html(validTime / 1000);
validTime = validTime - 1000;
if (validTime < 0) {
clearInterval(interval);
alert('Time Up!');
$('#textArea').prop('disabled', true);
$('#counter').html('start over');
$('#counterIsDone').on('click', function(){
$('#textArea').prop('disabled', false);
display30Seconds();
});
}
}, 1000);
}
but I see that I cannot call the method display30Seconds(); again. Or rather I can, but the interval is not set again. How can I fix it?
Seems like I'm not entering the code inside
if (!interval)
because the interval is not visible any more after clearing it (?). So I thought about moving the var interval; into the body of the method function display30Seconds() {, but that doesn't bring the expected effect. Is there a way of fixing it?
Here is my updated fiddle: http://jsfiddle.net/jf4ea4nx/3/
Set interval=null after the clearInterval() call.
What seems to confuse you is the semantics of clearInterval(interval). As Patrick Evans points out in his comment, it will not set interval to a value that evaluates to false in a condition.
To make it completely clear you could use a boolean variable such as countdownRunning in addition to the interval variable to keep track of whether the countdown is active or not.
Try this:
$('#textArea').on('input propertychange', display30Seconds);
var interval=false;
function display30Seconds() {
var validTime = 3000;
if (!interval)
interval = setInterval(function () {
$('#counter').html(validTime / 1000);
validTime = validTime - 1000;
if (validTime < 0) {
clearInterval(interval);
alert('Time Up!');
$('#textArea').prop('disabled', true);
$('#counter').html('start over');
$(document).on('click','#counterIsDone', function(){
$('#textArea').prop('disabled', false);
display30Seconds();
});
interval=false;
}
}, 1000);
}
You can improve your code by using a conditional recursive call to to your iterative function instead - each call has a one second delay, which makes it slightly more intuitive to use (think of each call as one tick):
var seconds = 3;
$('#textArea').on('input propertychange', setTimeout(timeout.bind(null, seconds), 1000));
function timeout (iterations) {
$('#counter').html(iterations);
if (iterations === 0) {
alert('Time Up!');
$('#textArea').prop('disabled', true);
$('#counter').html('start over');
$('#counterIsDone').on('click', function(){
$('#textArea').prop('disabled', false);
timeout(seconds);
});
}
else {
setTimeout(timeout.bind(null, --iterations), 1000);
}
}
The bind function simply binds the arguments of the bind function to the arguments of the timeout call - the first argument to the bind function declares its this scope; but don't worry about that too much.
You can modify the duration of the timer by changing the seconds var. Hope this helps :)

jQuery setInterval too fast when tab is inactive

When the tab my website is on is inactive, my slideshow starts switching pictures too fast and mess the whole thing up.
Is there a way i could fix this?
var img_src = ["1.png", "2.png", "3.png", "4.png"];
var delay = 8000;
var first_run = true;
function switch_pic(position){
$("#show").attr("src", img_src[position]).fadeOut(0).fadeIn(4000).fadeOut(4000);
}
$(document).ready(function(){
var i = 0;
if(first_run){
switch_pic(i);
first_run = false;
i++;
}
window.setInterval(function(){
switch_pic(i);
delay += 8000;
i++;
if(i > 3){
i = 0;
window.clearInterval();
}
}, delay);
});
Could wrap the code in this:
$(document).ready(function(){
$([window, document]).focusin(function(){
//code run when tab is selected
}).focusin(function(){
//code to stop all animation
});
});
That would only let the slideshow run when the user is viewing your site.
I'm not sure why things speed up. Normally the timers on background tabs will be slowed down to at least one second, but this shouldn't affect your scenario. I suggest using console.log() to track the calls to your functions.
Also, you can simplify your main loop a bit:
$(document).ready(function(){
var i = 0;
window.setInterval(function(){
switch_pic(i++); // increase i after call
if(i > 3) i = 0; // reset i
}, 8000);
});
I think that the answer good for actual version of jQuery should look like this:
var intervalId;
$([window, document]).on('focusin', function(){
intervalId = setInterval(function() {
// Action in interval
}, 3000);
}).on('focusout', function(){
if (intervalId) {
clearInterval(intervalId);
}
});
Pleas remember, that first time your 'focusin' is not tigger when page is loaded, so you should use this construction for this:
intervalFunction();
$([window, document]).on('focusin', function(){
if (!intervalId){
intervalFunction();
}
}).on('focusout', function(){
if (intervalId) {
clearInterval(intervalId);
intervalId = undefined;
}
});
function intervalFunction() {
// Your function hire
}

Hide download link for 10 seconds? js

hey, how can I have my download link hidden, and make a count down type thing. Maybe have it count down from 10 and once it's done that have the download link appear, it would be best to do it in js right?
does anyone know how to do this? :D
Thanks
Complete example:
<span id="countdown"></span>
<a id="download_link" href="download.zip" style="display:none;">Download</a>
<noscript>JavaScript needs to be enabled in order to be able to download.</noscript>
<script type="application/javascript">
(function(){
var message = "%d seconds before download link appears";
// seconds before download link becomes visible
var count = 10;
var countdown_element = document.getElementById("countdown");
var download_link = document.getElementById("download_link");
var timer = setInterval(function(){
// if countdown equals 0, the next condition will evaluate to false and the else-construct will be executed
if (count) {
// display text
countdown_element.innerHTML = "You have to wait %d seconds.".replace("%d", count);
// decrease counter
count--;
} else {
// stop timer
clearInterval(timer);
// hide countdown
countdown_element.style.display = "none";
// show download link
download_link.style.display = "";
}
}, 1000);
})();
</script>
You can use setInterval for this. setInterval behaves like a timer, where you can run a certain function periodically. Something like this should do the work(untested):
$(".link").hide();
var iteration = 0;
var timer = setInterval(function() {
if(iteration++ >= 10) {
clearTimeout(timer);
$(".link").show();
$(".counter").hide();
}
$(".counter").text(10 - iteration);
}, 1000);
This will initially hide the download link and run a function every second which counts down from 10. When we reaced ten, we hide the counter and show the link. ClearTimeout is used so that we don't count after we reached ten. Easy as dell.
Edit: As mentioned in the comments, this function is using jQuery to find the elements.
Take a look at the setTimeout function. You can do something like:
function displayLink() {
document.getElementById('link_id').style.display = 'block';
}
setTimeout(displayLink, 10000);
var WAIT_FOR_SECONDS = 10;
var DOWNLOAD_BUTTON_ID = "btnDownload";
if (document.body.addEventListener) {
document.body.addEventListener("load", displayDownloadButton, false);
} else {
document.body.onload = displayDownloadButton;
}
function displayDownloadButton(event) {
setTimeout(function() {
_e(DOWNLOAD_BUTTON_ID).style.display = "";
}, WAIT_FOR_SECONDS*1000);
}
function _e(id) {
return document.getElementById(id);
}

How to auto refresh HTML only if there has been no activity on a page?

I have a website which I would like to auto refresh ONLY if user is not using it for a specific time (ie.180 sec).Is there a way to auto refresh HTML only if there has been no activity on a page?
Thank you!
Two approaches:
1. Use a once-a-second timer and a "timeout" value.
You probably want to wrap this up in an object:
var activityHandler = (function() {
var timerHandle = 0,
timeout;
flagActivity();
function start() {
stop();
flagActivity();
timerHandle = setInterval(tick, 1000);
}
function stop() {
if (timerHandle != 0) {
clearInterval(timerHandle);
timerHandle = 0;
}
}
function flagActivity() {
timeout = new Date() + 180000;
}
function tick() {
if (new Date() > timeout) {
stop();
location.reload();
}
}
return {
start: start,
stop: stop,
flagActivity: flagActivity
};
})();
Then start it on page load:
activityHandler.start();
And ping it every time you see "activity":
activityHandler.flagActivity();
So for instance, you might do this:
if (document.addEventListener) {
document.addEventListener('mousemove', activityHandler.flagActivity, false);
}
else if (document.attachEvent) {
document.attachEvent('onmousemove', activityHandler.flagActivity);
}
else {
document.onmousemove = activityHandler.flagActivity;
}
2. Use a timer you reset every time there's "activity".
This is less ongoing work (we don't have something happening every second), but more work when you flag that activity has happened.
Set up a timer to do the refresh:
var handle = setTimeout(function() {
location.reload();
}, 180000);
...and then cancel and reschedule any time you see whatever you consider to be "activity":
clearTimeout(handle);
handle = setTimeout(...);
You can wrap this up in a function:
var inactivityTimerReset = (function() {
var handle = 0;
function reset() {
if (handle != 0) {
clearTimeout(handle);
}
handle = setTimeout(tick, 180000);
}
function tick() {
location.reload();
}
return reset;
})();
// Kick start
inactivityTimerReset();
// ...and anywhere you see what you consider to be activity, call it
// again
inactivityTimerReset();
Then, again, ping it on every activity. But this is a lot more work than I'd put in a mousemove handler, hence solution #1 above.
var docTimeOut;
function bodyTimeOut()
{
docTimeOut=setTimeout(function(){location.reload();},18000);
}
function resetTimeOut()
{
clearTimeout(docTimeOut);
bodyTimeOut();
}
document.onload = bodyTimeOut;
document.body.onmouseover= resetTimeOut;
you could declare a variable pageActive or something, set it to false, and whenever user does something set it to true.
Then, set a function to execute periodically as frequently as you want with setinterval() that checks this variable, if it's true set it to false to start again, if is false then refresh page.
You can use onblur and onfocus on body element to see if there is a kind of activity on your page.

Categories

Resources