Why isn't my code running before the interval completes? - javascript

In the snippet, I want the color of timer to change to red before the alert pops up.
I have written $("#timer").css('color', 'red'); before alert("Time Up!"), so logically it should change the text color before showing the alert, but it is changing color after displaying the alert.
let time = 3;
$(function() {
let interval = setInterval(function() {
time--;
if (time >= 0)
document.getElementById("timer").innerHTML = time + "";
else {
$("#timer").css('color', 'red');
clearInterval(interval);
alert("Time Up!")
}
}, 1000);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 id="timer">3</h1>

The issue is because the alert() blocks the UI from updating, and although you call css() before alert(), there's not enough time to update the DOM before the alert appears and temporarily prevents any further rendering.
To fix this, place the alert() call in a timeout with a short delay. This allows the UI to be updated before the alert() is displayed:
let time = 3;
jQuery($ => {
let interval = setInterval(function() {
time--;
if (time >= 0) {
$("#timer").html(time);
} else {
$("#timer").css('color', 'red');
clearInterval(interval);
setTimeout(() => alert("Time Up!"), 0);
}
}, 1000);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<h1 id="timer">3</h1>

Related

How can I reset the timer again using clearInterval()?

I have looked at the other threads about this question, but so far I have found no solution that fits my problem. I want to create a timer that activates using an addEventListener, in which I will use a setInterval(). Then I want to have a "pause" button that can pause the setInterval(), which I did by using clearInterval().
My problem is that, once I pause my timer once, I cannot get the timer to continue counting again by clicking the same button that starts the timer in the first place. This is my code:
hour=document.getElementById("hour");
minute=document.getElementById("minute");
second=document.getElementById("second");
start=document.getElementById("start")
reset=document.getElementById("reset")
pause=document.getElementById("pause");
var countdown;
start.addEventListener("click", function clicked() {
countdown = setInterval(function() {
if (second.textContent!="59") {
let new_second=Number(second.textContent)+1;
second.textContent=new_second;
}
else {
second.textContent="00";
if (minute.textContent!="59") {
let new_minute=Number(minute.textContent)+1;
minute.textContent=new_minute;
}
else {
minute.textContent="00";
let new_hour=Number(hour.textContent)+1;
hour.textContent=new_hour;
}
}
}, 1000)
this.outerHTML=this.outerHTML;
}, false);
pause.addEventListener("click", function() {
clearInterval(countdown);
})
reset.addEventListener("click",function() {
clearInterval(countdown);;
second.textContent="00";
minute.textContent="00";
hour.text.Content="00";
})
Thank you all for your help!
outerHTML destroys the original start button (and creates a new instance), and thus the event listener you attached to it is no longer valid. Fixed code here:
hour=document.getElementById("hour");
minute=document.getElementById("minute");
second=document.getElementById("second");
start=document.getElementById("start")
reset=document.getElementById("reset")
pause=document.getElementById("pause");
var countdown;
start.addEventListener("click", function clicked() {
// alternatively you can clearInterval here every time
if(!countdown)
countdown = setInterval(function() {
if (second.textContent!="59") {
let new_second=Number(second.textContent)+1;
second.textContent=new_second;
}
else {
second.textContent="00";
if (minute.textContent!="59") {
let new_minute=Number(minute.textContent)+1;
minute.textContent=new_minute;
}
else {
minute.textContent="00";
let new_hour=Number(hour.textContent)+1;
hour.textContent=new_hour;
}
}
}, 1000)
}, false);
pause.addEventListener("click", function() {
clearInterval(countdown);
countdown=null;
})
reset.addEventListener("click",function() {
clearInterval(countdown);
countdown=null;
second.textContent="00";
minute.textContent="00";
hour.textContent="00";
})
<div id="hour"></div>
<div id="minute"></div>
<div id="second"></div>
<div id="start">start</div>
<div id="reset">reset</div>
<div id="pause">pause</div>

clearInterval() not working in an if/else statement with recursive function

I am trying to build a countdown that switches between play time and work time. It starts with 10 seconds of work then when it reaches 0 seconds we clear the interval and set it to 'play' and call the function again...
var model = {
intervalID: 0,
status: 'work',
workSeconds: 10,
playSeconds: 10,
}
function startCountdown(){
if (model.status === 'work') {
model.countdown = model.workSeconds;
model.intervalID = setInterval(function(){
model.countdown--;
if (model.countdown > 0) {
console.log('work', model.countdown);
} else {
model.status = 'play';
clearInterval(model.indervalId);
startCountdown();
}
}, 1000);
} else if (model.status === 'play') {
model.countdown = model.playSeconds;
model.intervalID = setInterval(function(){
model.countdown--;
if (model.countdown > 0) {
console.log('play', model.countdown);
} else {
model.status = 'work';
clearInterval(model.indervalId);
startCountdown();
}
}, 1000);
}
}
startCountdown();
This function is supposed to console log a 10 second countdown for work, then when the countdown reaches 0 switch to a 10 seconds countdown of play, and keep doing that.
At the moment it looks like no intervals are being cleared and both intervals just keep setting each other in a feedback loop.
Why are the intervals not being cleared?
I think you have a typo. clearInterval(model.indervalId); should be clearInterval(model.intervalID);.
I'd use setTimeout for this too, but I guess you already know about that.

Javascript auto page refresh code

this is the code that comes in head section and it will automatically refresh the whole page in 1 min as i put 6000 in the code below
<script type="text/javascript">
setTimeout('window.location.href=window.location.href;', 6000);
</script>
is there any way for example, when there's 10 seconds left to refresh the page then, a button will display and say "Click here to reset timer" and it will reset that timer to 1 min again?
<script language="javascript">
var timeout,interval
var threshold = 15000;
var secondsleft=threshold;
startschedule();
window.onload = function()
{
startschedule();
}
function startChecking()
{
secondsleft-=1000;
if(secondsleft <= 10000)
{
document.getElementById("clickme").style.display="";
document.getElementById("timercounter").innerHTML = Math.abs((secondsleft/1000))+" secs";
}
}
function startschedule()
{
clearInterval(timeout);
clearInterval(interval);
timeout = setTimeout('window.location.href=window.location.href;', threshold);
secondsleft=threshold;
interval = setInterval(function()
{
startChecking();
},1000)
}
function resetTimer()
{
startschedule();
document.getElementById("clickme").style.display="none";
document.getElementById("timercounter").innerHTML="";
}
</script>
Please wait...<span id="timercounter"></span>
<button id="clickme" style="display:none;" onclick="javascript:resetTimer();">Click here to reset timer</button>
Assuming you have the following html for the button:
<button id="cancel-reload-button" style="display: none" onclick="cancelReload()">Cancel Reload</button>
And this as the script (Note: this gives the idea, but is not neccesarily fully tested):
// Variable for holding the reference to the current timeout
var myTimeout;
// Starts the reload, called when the page is loaded.
function startReload() {
myTimeout = setTimeout(function() {
document.getElementByID("cancel-reload-button").style.display = "inline";
myTimeout = setTimeout(function() {
window.location.reload();
} 10000)
}, 50000);
}
// Cancel the reload and start it over. Called when the button is
// clicked.
function cancelReload() {
clearTimeout(myTimeout)
startReload()
}
// On page load call this function top begin.
startReload();
I created two functions, one for starting the reload and the second one for cancelling it.
Then I assigned the timeout to the variable myTimeout which can be used to later cancel the timeout.
Then I called myTimeout twice - Once for 50 secs, at which point it shows the button and once for 10 secs after which it finally reloads.
How about below? If you click on OK to reset timer, it would keep giving the confirm box every 50 seconds. If you click cancel, it will refresh the page in 10 seconds.
setInterval(function(){ var r = confirm("Reset Timer");
if (r == true) {
setTimeout('window.location.href=window.location.href;', 60000);
} else {
setTimeout('window.location.href=window.location.href;', 10000);
}
}, 50000);
Note: In your question you specified 1 minute, but your code works for 6 seconds(6000 -- > 6 seconds not 60 seconds) I have included for a minute
You can use 2 setTimeout calls, one to make the "Reset" button show up and another one for the refresh timer reset. The trick is to store the second setTimeout on a global variable and use clearTimeout to reset it if the button is pressed.
Here is some JavaScript code to illustrate:
<script type="text/javascript">
var autoRefreshTime = 30 * 1000; // 60000ms = 60secs = 1 min
var warningTime = autoRefreshTime - (10 * 1000); // 10 secs before autoRefreshTime
waitTimeout = setTimeout('window.location.href=window.location.href;', autoRefreshTime);
warningTimeout = setTimeout('ShowResetButton();', warningTime);
function ShowResetButton() {
// Code to make the "Reset" button show up
}
// Make this function your button's onClick handler
function ResetAutoRefreshTimer() {
clearTimeout(waitTimeout);
waitTimeout = setTimeout('window.location.href=window.location.href;', autoRefreshTime);
}
</script>
The way I would do it is make a function with a timeout, and invoke that function
<script type="text/javascript">
var refreshFunc = function(){
setTimeout(function(){
var r = confirm("Do you want to reset the timer?");
if(r === false){
window.location.href=window.location.href;
}else{
refreshFunc();
}
}, 6000);
};
refreshFunc();
</script>
One big problem with using confirm in this case is you cannot program it to reject. You would have to implement you own modal/dialog box so you can auto reject in 10 seconds.
Try using setInterval():
var time;
$(function() {
time = $('#time');
$('#reset').on('click', reset);
start();
});
var timer, left;
var start = function() {
left = +(time.text()); //parsing
timer = setInterval(function() {
if (0 <= left) {
time.text(left--);
} else {
clearInterval(timer);
location.replace(location);
}
}, 1000);
};
var reset = function() {
if (timer) {
clearInterval(timer);
}
time.text('59');
start();
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h1><span id='time'>59</span> second(s) left</h1>
<input id='reset' value='Reset' type='button' />

Simple JavaScript counter function

I would like to make a counter function, and precise a variable for the starting time and the place to be displayed.
So if I would like to have many counter per page, I can easily manage it:
$(document).ready(function() {
// set time and place (where to display the counter)
function countDown(time, place){
if(time > 0){
time--;
setInterval(function(){countDown(time,place)}, 1000);
} // end if
if(time == 0)
{
window.clearInterval(time);
}
} // end function
$('.click').click(function(){
countDown(30, '#counter');
});
}); // end DOM
</script>
</head>
<body>
<div class="click">clickme</div>
<br />
<div id="counter">30</div>
</body>
Try this:
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js">
</script>
<script>
var myVar;
var clickcount=0;
function countDown (time, place) {
if (time > 0) {
$(place).html(time);
time--;
myVar=setTimeout(function () { countDown(time, place); }, 1000);
}
}
function startreset(time,place){
clickcount++;
if(clickcount % 2 === 0){
clearTimeout(myVar);
} else {
countDown(time,place);
}
}
$('.click').click(function(){
startreset(30, '#counter');
});
</script>
</head>
<body>
<div class="click" onClick="javascript:countDown(30,'#counter');">clickme</div>
<br />
<div id="counter">30</div>
</body>
The problem you are likely having is that you are calling setInterval multiple times. setInterval does more than just wait the x milliseconds you tell it to and then call your method, it continues to call your method every subsequent x milliseconds. So, when you call countDown the first time, an interval is set for your function. That interval expires and countDown is called again. All fine so far, but now the second call to countDown establishes ANOTHER setInterval. The program will wait your x milliseconds to call countDown from the second setInterval, but it will call it from the first setInterval sooner.
...In other words, you shouldn't be repeatedly calling setInterval. What you want is setTimeout, which waits the specified amount of time and then calls the specified method once.
function countDown (time, place) {
if (time > 0) {
time--;
$(place).html(time);
setTimeout(function () { countDown(time, place); }, 1000);
}
}
Alternatively, if you're not feeling recursive today:
function countDown (time, place) {
var interval = setInterval(function () {
if (time > 0) {
time--;
$(place).html(time);
} else {
window.clearInterval(interval);
}
}, 1000);
}
which leverages setInterval, BUT ONLY ONCE.
JSFiddle provided: http://jsfiddle.net/LKvBR/

Duplicated countdown timer after click event

I have this function:
var secondsRemaining = 45;
function countdown(secondsRemaining) {
var seconds = secondsRemaining;
if (secondsRemaining > 0) {
$('.timer > div').html(seconds);
secondsRemaining--;
} else {
if (secondsRemaining == 0) {
// Times up ....
}
}
setInterval(function() {
countdown(secondsRemaining);
}, 1000);
}
I am running the function in the Document ready function with:
countdown(secondsRemaining);
and also I run it again after I clicked for answer.
the problem is that I have 2 countdown timer now running simultaneously, new one that start from 45 seconds and the old one that continue from where it was.
Use clearInterval()
First, store the interval id of the first setInterval():
var secondsRemaining = 45;
function countdown(secondsRemaining) {
var seconds = secondsRemaining;
if (secondsRemaining > 0) {
$('.timer > div').html(seconds);
secondsRemaining--;
} else {
if (secondsRemaining == 0) {
// Times up ....
}
}
myinterval=setInterval(function() { //myint now contains the interval id
countdown(secondsRemaining);
}, 1000);
}
Now, when the user clicks, before setting up a new interval, cancel the first one with clearInterval():
button.onclick=function(){
//do stuff
clearInterval(myinterval)
setInterval(function() {
countdown(secondsRemaining);
}, 1000);
// do stuff
}
Sorry I don't really understand the way you have phrased the question seems to say that you intentionally want to start two time events, one when the document has loaded and the other when you click answer which are both outputting to the same element.
If the problem is you want it to have the output in two different elements then you could pass an argument of the element you could use:
countdown($('.pick-me'), secondsRemaining);
If you want to use the same element, then you could always clear the interval on each click and then set the interval for the new event, just got the update and seen Manishearths response so wont go into any more detail about it as that's probably the answer you are looking for.

Categories

Resources