How can i display the right numbers in my counting - javascript

I want to count down a counter. However, it always starts one number later. I know the problem, but I can't find the solution.
function countStart() {
const countdown = setInterval(() => {
time -= 1;
document.getElementById('counter').textContent = time;
if (time < 1) {
clearInterval(countdown);
}
}, 1000);
}
If I count down from 10. If it starts at 9, how do I change that?

You are decreasing your "time" variable before you display it. So if your "time" variable has a value of 10 initially, it will get reduced to 9 before being displayed due to the statement "time -=1" occuring before setting it as textContent for your element (and thus displaying it).
Try decreasing your "time" variable after setting it as textContent of your counter element.
function countStart() {
const countdown = setInterval(() => {
document.getElementById('counter').textContent = time;
time -= 1;
if (time < 1) {
clearInterval(countdown);
}
}, 1000);
}

you just put time-=1 below the line where you change DOM
function countStart(time) {
const countdown = setInterval(() => {
//document.getElementById('counter').textContent = time;
console.log(time)
time -= 1;
if (time < 1) {
clearInterval(countdown);
}
}, 1000);
}
just changed dom manipulation to console.log

Related

Need Help Coding a Loop Using "For" Statement in JavaScript

I need to make a countdown happen from 10 to 0 using a loop. The loop should replace the need to repeat the code 10X. I also neeed to display the countdown to the user in the HTML. Help!
<script>
function StartTheCountdown()
{
var Countdown = 10;
// Used to keep track of actual time.
// 1000 = 1 second because we are using milliseconds.
var timeout = 10000;
setTimeout(() => {
document.getElementById("CountDownDisplay").innerHTML = "Blastoff!";
Countdown = Countdown - 1;
}, timeout)
timeout = timeout - 1000;
// We need to do this 10 times **************************************
setTimeout(() => {
document.getElementById("CountDownDisplay").innerHTML = Countdown;
Countdown = Countdown - 1;
}, timeout)
timeout = timeout - 1000;
}
</script>
Use setTimeout to repeatedly call the function until count is zero, and then display a message.
// Cache your element
const div = document.querySelector('div');
// Initialise your count to 10
function countdown(count = 10) {
// Update your element textContent
div.textContent = `T-minus: ${count}`;
// Call the function again if the count
// is greater than 0 with a decremented count
if (count > 0) {
setTimeout(countdown, 1000, --count);
// Otherwise update the textContent of the
// element with a message
} else {
div.textContent = 'Blast off!';
}
}
countdown();
<div></div>
Additional documentation
Template/string literals

setInterval goes to negative

I'm buidling this pomodoro app.
https://jsfiddle.net/yvrs1e35/
I got few problems with the timer.
startBtn.addEventListener('click', function(){
minutes.innerHTML = sessionTime.innerHTML - 1
seconds.innerHTML = 59
var timer = setInterval(()=>{
if(Number(minutes.innerHTML) != 0 && Number(seconds.innerHTML) != 0){
seconds.innerHTML--
if(Number(seconds.innerHTML) == 0){
seconds.innerHTML = 59;
minutes.innerHTML--
}
}else if (Number(minutes.innerHTML) == 0 && Number(seconds.innerHTML) == 0){
clearInterval(timer)
}
},1000)
resetBtn.addEventListener('click', function(e){
e.preventDefault();
breakTime.innerHTML = 5
sessionTime.innerHTML = 25
minutes.innerHTML = "00"
seconds.innerHTML = "00"
clearInterval(timer)
})
pauseBtn.addEventListener('click', function(e){
e.preventDefault();
})
})
It works if the timer if there is more than 1 minute left on the interval.
If it goes under 1 minute, even though i have this if in the interval
else if (Number(minutes.innerHTML) == 0 && Number(seconds.innerHTML) == 0){
clearInterval(timer)
}
seconds and minutes go on negative ( after 0:0, timer shows -1:59)
I though that else if statement would stop the interval when both minutes and seconds reach 0, but it doesnt for some reason.
#also if i press startbtn multiple times, the timer starts multiple times, and the seconds go 2x 3x 4x faster, how can I stop the startbtn until the timer reaches 0:0?
Can i get any help?
.innerHTML is an expensive operation. Storing data inside the DOM like this is an antipattern; extracting it and manipulating it stringifies and de-stringifies numbers for no reason. Store state in your JS script and update the DOM content only when a rendering change is necessary. In other words, consider it write-only.
The interval runs multiple times; you'll need a flag to prevent re-triggers (or clearInterval before resetting it). Setting interval to undefined is a good way to indicate that the clock isn't running.
Lastly, setInterval with a cooldown of 1000 is a poor choice for timekeeping. It will drift quite a bit depending on scheduling interruptions and other random factors; the 1000 means "wait at least 1000 milliseconds before firing the callback". Instead, use Date for accuracy.
I'd work entirely in milliseconds and convert to minutes and seconds only for the formatted output. This follows the principle described in the first paragraph about separating presentation from logic.
Here's a proof of concept to illustrate the above points. Of course, if you're doing the pomodoro for fun, sticking to setInterval(() => ..., 1000) does make the code simpler, but I think it's instructive to see it from a couple angles if nothing else.
const padTime = t => (Math.floor(t) + "").padStart(2, 0);
const timeFmt = t => `${padTime(t / 60000)}:${
padTime(t / 1000 % 60)}`;
const run = () => {
interval = setInterval(() => {
if (interval) {
display.textContent = timeFmt(end - Date.now());
}
if (Date.now() >= end) {
clearInterval(interval);
interval = undefined;
}
}, 100);
};
let interval;
let pause;
const initialMinutes = 2;
const duration = initialMinutes * 60000;
const time = Date.now();
let end = time + duration;
const display = document.querySelector("h1");
display.textContent = timeFmt(end - time);
const [startBtn, pauseBtn, resetBtn] =
document.querySelectorAll("button");
startBtn.addEventListener("click", e => {
clearInterval(interval);
if (!interval) {
if (pause) {
end += Date.now() - pause;
pause = undefined;
}
else {
end = Date.now() + duration;
}
}
run();
});
resetBtn.addEventListener("click", e => {
clearInterval(interval);
interval = undefined;
const time = Date.now();
end = time + duration;
display.textContent = timeFmt(end - time);
});
pauseBtn.addEventListener("click", e => {
if (interval) {
pause = Date.now();
clearInterval(interval);
interval = undefined;
}
});
<h1></h1>
<div>
<button>start</button>
<button>pause</button>
<button>reset</button>
</div>
if(Number(minutes.innerHTML) != 0 && Number(seconds.innerHTML) != 0)
Changing the "&&" to "||" should fix one problem (which is that it is stuck at 0:59). If you add another condition to
if(Number(seconds.innerHTML) == 0){
where the if condition is only true, if seconds == 0 AND minutes > 0, then all problems should be solved.
Your negative time comes from starting at 0 and because of this:
minutes.innerHTML = sessionTime.innerHTML - 1
seconds.innerHTML = 59
It changes minutes to negative value and sets seconds to 59. You should add some validation before this and don't start clock.
setInterval doesn't guarantee that your function will execute in the precise interval, just that it wouldn't execute earlier. This way, on a slow/loaded computer, the function could be called after the interval is already elapsed.
In other words, you probably wish to check if the timer has already elapsed, not if it's just about to do so.
(Number(minutes.innerHTML) <= 0 && Number(seconds.innerHTML) <= 0)

How to get seconds to countdown properly after button click event

To start, I am brand new to Javascript so please excuse my naivete.
I am working on a countdown timer to start on a button click. The timer does start on the click, however, the seconds timer immediately changes (minus 1) and then after that proceeds to countdown every second (as desired).
for example: timer is at 25:00.
button is clicked, timer immediately drops to 24:59 (without a second passing)
then proceeds to countdown as normal.
Thank you in advance.
let min = 25;
let sec = 60;
let remainSec = sec % 1;
let minText = document.getElementById('minutes');
minText.innerText = min; //declared outside of sample
let secondsText = document.getElementById('seconds');
secondsText.innerText = remainSec + '0' ; //declared outside of sample
startTime.addEventListener('click', decrement); //declared outside of sample
function decrement() {
sec--;
secondsText.innerText = sec;
if (sec < 10){
secondsText.innerText = '0' + sec;
}
setInterval(decrement, 1000);
}
You can use a timeout:
startTime.addEventListener('click', function() { setTimeout(decrement,1000) });
You don't need the setInterval inside the decrement function, this way it will be called multiple times, and the decrement will occur more then once per second.
Do something like this:
startTime.addEventListener('click', decrement); //declared outside of sample
let interval;
function startDecrement() {
if (!interval) { // avoid duplicate interval
interval = setInterval(decrement, 1000);
}
}
function decrement() {
sec--;
secondsText.innerText = sec;
if (sec < 10){
secondsText.innerText = '0' + sec;
}
}
Another cool stuff is that storing the interval allows you cancelling it using the [clearInterval()](
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearInterval) function.
function stopDecrement() {
clearInterval(interval);
interval = null;
}
Additional information
The if statement that checks if a interval was already declared works because javascript any value in a Truthy or Falsy value when using with ! (NOT operator). See Understanding JavaScript Truthy and Falsy
So, when you call setInterval() it returns an unique non-zero integer that identifies the interval, allowing you to cancel it in the future.
On the first run, the interval variable is empty because we just declared it without a value.
let interval;
console.log(interval); // undefined
console.log(!interval); // true
interval = setInterval(decrement, 1000);
console.log(interval); // 1
console.log(!interval); // false

How to make setInterval method have only one instance running

I have a button that, when clicked, starts a timer and decreases the integer by 1 per second.
However, if the button is clicked multiple times, the integer decreases by a lot more than 1 per second, due to setInterval being called multiple times.
How do I make it so that, even though the button is clicked multiple times, the timer only goes down by 1 each second (I do not want to disable the button).
var time = document.getElementById("time");
document.getElementById("Btn").addEventListener("click", () => {
var decreaseTime = setInterval(() => {
if (time.textContent != 0) {
time.innerHTML = time.textContent - 1;
}
}, 1000);
if (time.textContent == 0) {
clearInterval(decreaseTime);
}
});
You should define your decreaseTime variable in a higher scope and then check if it exists prior to defining your interval. For instance:
var time = document.getElementById("time");
decreaseTime = undefined;
document.getElementById("Btn").addEventListener("click", () => {
if(!decreaseTime){
decreaseTime = setInterval(() => {
if (time.textContent != 0) {
time.innerHTML = time.textContent - 1;
}
}, 1000);
if (time.textContent == 0) {
clearInterval(decreaseTime);
}
}
});

Timer counting faster on second run

I am working on a simple game right now. its almost done except for the timer has a glitch in it and I can't figure out whats doing it. when you push a button, an HTML5 text on the canvas starts to count down from 35 to 0. On the first run it's fine. But if you choose to play again with out refresh the timer starts to countdown faster. here is the code.
var timer = 35;
ctx.fillText("Countdown: " + timer, 320, 32);
function resetReggie(){
reggie.x = canvasWidth / 2;
reggie.y = canvasHeight / 2;
}
//Starts Timer for Timed Game
function timedMsg()
{
resetReggie();
ballsCaught = 0;
timer = 35;
alert('Pick up as many as you can in ' + timer + ' seconds');
countDown();
var t=setTimeout(function() {
var again = confirm("TIMES UP! You Gathered " + ballsCaught + " Balls! Play Again?");
if (again === true){
timedMsg();
resetReggie();
}
if (again === false){
resetReggie();
ballsCaught = 0;
timer = 35;
}
}, timer * 1000);
}
function countDown() {
if (timer != 0){
timer-=1;
setTimeout('countDown()', 1000);
}
}
I think the problem is in the line
}, timer * 1000);
where you have a value that is at most 34 at the time 'timer' is evaluated to set the timeout. Because you initialize it to 35 but then call countDown() which decreases it to 34, then you have a call to confirm() which might let 'timer' decrease even more. As a result the subsequent call to timedMsg() happens a little too soon causing countDown() to be called twice as often. Try the following (I ran it in node) and then change the 4 to 6.
function countDown() {
console.log("Countdown: " + timer, 320, 32);
if (timer != 0) {
timer -= 1;
setTimeout(countDown, 1000);
}
}
function timedMsg() {
timer = 5;
countDown();
var t=setTimeout(function() {
timedMsg();
}, 4 * 1000);
}
timedMsg();
As mentioned in my comment, each time you start a new game, it appears you are decreasing the timeout value. As a result, this reduces the time each time.
Try this:
var timeout = currentTime = 5;
var int = setInterval(function() {
​console.log(currentTime);
currentTime--;
if(currentTime < 0) {
var again = confirm('Play again?');
if(again) {
currentTime = timeout;
}
else {
clearInterval(int);
}
}
}, 1000);​
http://jsfiddle.net/gRoberts/CsyYx/
Look at your console (F12 in Chrome), or update the code to write to the browser to see it working ;)

Categories

Resources