How do I alert when a certain value is met - javascript

So I'm making a timer in html and javascript and I am displaying it on a button. I want to make it so that when the value of time is equal to zero, it alerts the user. Here is my code so far. btw, the code is part of the timer code.
const time2=
document.getElementById("countdown")
if(time2==0:00)
alert("You have ran out of time, better luck next time!")

You can create a timer with a setInterval() and trigger some functionality when a value is reached, in this case the timer is cleared, i hope this helps:
const createTimer = (num) => {
const timer = setInterval(() => {
console.log(num)
num--;
if(num == 0) {
console.log("You have ran out of time, better luck next time!")
clearInterval(timer)
}
}, 1000)
}
createTimer(4)

something like this?
let div = document.getElementById('count')
let countdown = 10
let stopper = setInterval(myTimer, 1000)
function myTimer() {
countdown--
div.innerHTML = countdown + " seconds left"
if (countdown == 0) {
clearInterval(stopper)
}
}
<div id='count'>10 seconds left</div>

Here is one possible implementation of a very simple Timer using a class. Most important is setInterval() which will allow you to run a function every x milliseconds.
This timer uses a callback function onUpdate(seconds) which is called every time the timer is updated and provides the remaining seconds as a parameter. You could certainly extend on that.
It is also required to wait for the HMTL document to have loaded before trying to access the DOM using the DOMContentLoaded event.
class Timer {
#interval;
#initial;
#seconds;
constructor(seconds, onUpdate) {
this.#initial = seconds;
this.#seconds = seconds;
this.onUpdate = onUpdate;
this.onUpdate(seconds);
}
start() {
this.#interval = setInterval(() => {
this.#seconds--;
if (this.#seconds === 0) this.stop();
this.onUpdate(this.#seconds);
}, 1000);
}
reset() {
this.stop();
this.#seconds = this.#initial;
this.onUpdate(this.#seconds);
}
stop() {
clearInterval(this.#interval);
this.onUpdate(this.#seconds);
}
}
// wait for HTML document to load
window.addEventListener("DOMContentLoaded", e => {
const startBtn = document.getElementById("start");
const stopBtn = document.getElementById("stop");
const resetBtn = document.getElementById("reset");
// create a timer and assign it seconds as well as a callback function that is called every second
const timerDiv = document.getElementById("countdown");
const timer = new Timer(5, (seconds) => {
// called every seconds with seconds to go as an argument
timerDiv.textContent = `${seconds}s to go`
})
// add event listeners to buttons
startBtn.addEventListener("click", () => timer.start());
stopBtn.addEventListener("click", () => timer.stop());
resetBtn.addEventListener("click", () => timer.reset());
})
<div id="countdown"></div>
<button id="start">Start</button>
<button id="stop">Stop</button>
<button id="reset">Reset</button>

Related

Different intervals for setTimeout in useEffect

I am trying to achieve a situation when a function inside setTimeout is executed after X seconds first time, and then regularly at Y interval.
useEffect(() => {
let firstTime = true;
const timer = setTimeout(() => {
getValue(id).then((res) => {
setValue(res);
});
if (firstTime) {
firstTime = false;
}
}, firstTime ? 30000 : 60000);
return () => clearTimeout(timer);
}, [])
This doesn't work, however, as it sets firstTime to false before running the function. Is there a way to graciously achieve the result? Is it even possible with setTimeout?
You can use a variable as the setTimeout delay. In this case you would set firstTime to the delay you wanted to use the first time (30000), and then inside timer you would use if (firstTime == 30000) { firstTime = 60000; }. Using a different variable name here would make sense. Then set the setTimeout delay to just firstTime like }, firstTime);
Hopefully this is actually what you wanted.
useEffect(() => {
let firstTime = 30000;
const timer = setTimeout(() => {
getValue(id).then((res) => {
setValue(res);
});
if (firstTime == 30000) {
firstTime = 60000;
}
}, firstTime);
return () => clearTimeout(timer);
}, [])
Old (incorrect) answer:
You can use setTimeout with an initial delay to initialise a setInterval, which will repeat subsequent times at a different interval.

I need to call ClearInterval from a different function

I'm creating a countdown timer and I need to call clearInterval from a different function as I want to start and pause the countdown with two different buttons
Here's a piece of my code
const startCountdown = () => {
const countdown = setInterval(() => {
setSecondsElapsed(secondsElapsed => secondsElapsed - 1);
}, 1000);
};
const pauseCountdown = () => {
clearInterval(countdown);
};
The countdown starts when I press the initial button but it doesn't pause when I press the button calling pauseCountdown()
Use a React ref to hold the timer reference. When setting the interval store the countdown reference as the ref's current value, and in the other function clear the interval using the ref's current value.
const countDownRef = React.useRef();
const startCountdown = () => {
countDownRef.current = setInterval(() => {
setSecondsElapsed(secondsElapsed => secondsElapsed - 1);
}, 1000);
};
const pauseCountdown = () => {
clearInterval(countDownRef.current);
};
try declaring countdown globally so it can be accessed from any function. I'd also recommend using var instead of const for things that will be frequently redefined, such as a pausable countdown loop.
try this:
var countdown;
const startCountdown = () => {
countdown = setInterval(() => {
setSecondsElapsed(secondsElapsed => secondsElapsed - 1);
}, 1000);
};
const pauseCountdown = () => {
clearInterval(countdown);
};
The countdown value is inside the scope of startCountdown function hence it can not be accessed from pauseCountdown function which is not inside that very scope.
There are many different ways to do this job properly. I would advise you to be more structural with the help of new abstractions.
I may perhaps use a Countdown class for this job.
class Countdown {
#sid;
#start;
constructor(start){
this.#start = start;
}
startCountdown(){
this.#sid = setInterval( _ => ( !this.#start && clearInterval(this.#sid)
, console.log(this.#start--)
)
, 1000
);
}
pauseCountdown(){
clearInterval(this.#sid);
}
}
var cd = new Countdown(10);
cd.startCountdown();
setTimeout(_ => cd.pauseCountdown(), 5001)
setTimeout(_ => cd.startCountdown(), 10000)
The private class fields #sid and #start keep the clearInterval id and starting value respectively. The thing is they are not exposed to the outer world.

How does clearTimeout work, for clearing timeouts when the previous one is still running?

I'm creating a play & pause button for my video. This video will disappear when the timeout is done, because it will toggle the .active class off, which will return it back to 0 opacity. I've tied this to a onmousemoveFor this I'm using the clearTimeout.
I can't get it to work. The play button will flicker, because the class keeps getting added.
This is my function
const togglePlay = (...args) => playButton.classList.toggle(...args);
var timer = null;
vid.onmousemove = function(){
if (timer!= null){
clearTimeout(timer);
}
else {
togglePlay("active");
timer = setTimeout(() => {
togglePlay("active");
stopTime();
}, 2000);
}
}
I've already read multiple other post with this same problem. I tried implementing this: How to use clearTimeout
And I got the timer=null from another post.
I've also attemped it in anotherway, by disabling the togglePlay instead. This did work for what I wanted achieve, but by testing the console log, it was still firing a lot in the background.
I did that like this
var timer = null;
vid.onmousemove = function(){
if (timer != null){
console.log("TimedOut");
}
else {
//right here is the mistake, this is not a timer
timer = togglePlay("active");
setTimeout(() => {
togglePlay("active");
timer = null;
console.log("setTimeout");
}, 2000);
}
}
This code kind of defeats the purpose of the clearTimeout though. So my question really. What am I doing wrong with the setTimeout?
You first shown function should work fine if you remove the call to togglePlay right before you call setTimeout:
const vid = document.querySelector('#foo');
const togglePlay = (...args) => vid.classList.toggle(...args);
var timer = null;
vid.onmousemove = function(){
if (timer){ clearTimeout(timer); }
timer = setTimeout(() => {
togglePlay("active");
// stopTime();
}, 500);
}
#foo {
width: 300px;
height: 200px;
background: #c00;
}
#foo.active {
background: #090;
}
<div id="foo"></div>
This code debounces the action with each mousemove. If you want to have throttling, do it this way:
const vid = document.querySelector('#foo');
const togglePlay = (...args) => vid.classList.toggle(...args);
var timer = null;
vid.onmousemove = function(){
if (!timer){
timer = setTimeout(() => {
togglePlay("active");
timer = null;
// stopTime();
}, 500);
}
}
#foo {
width: 300px;
height: 200px;
background: #c00;
}
#foo.active {
background: #090;
}
<div id="foo"></div>
It looks like you want to use the timer to implement a cool-down period during which no class change should be allowed.
In that case do nothing when the timer variable is non-null, but also set the variable back to null when the delay has expired:
var timer = null;
vid.onmousemove = function(){
if (timer !== null) return; // Don't do anything if cool-down period is not yet over
togglePlay("active");
timer = setTimeout(() => {
togglePlay("active");
timer = null; // Cool-down is over now.
stopTime();
}, 2000);
}
If I understood well your problem, you probably need to store timerid on an array instead on a simple variable. Use:
var timers = [];
and
timers.push(setTimeout(...));
and for clear timeouts use:
if (timers.length > 0)
and then:
for (var i = 0; i < timers.length; ++i) {
clearTimeout(timers[i]);
}
timers = [];
However I personally do not like to use clear timeout option. Instead I usually use timer instance both stored on a local variable and passed to timeout as a parameter. Then I check inside the timer if this is the lastone called or if it is the one that I'm interested in.
var localctr = 0;
setTimeout(function(thisctr) {
if (thisctr == localctr) {
// ... this is the latest
}
}, 2000, ++localctr);
On this approach if you increase localctr on other event will effectively disable the timer.

How to run a timer in React component for 60 seconds and call a Redux action every 5 seconds

I have a react container, where I want to run a timer for 60 seconds and every 5 seconds I want to dispatch an action. This action is calling an api and returning some result.
One more thing to be handled is suppose my action return error after 3rd call i.e. after 15 seconds, then how can I stop the timer thereafter.
handleSimulateButton = (e) => {
/*
Once I click on Simulate button, I want the below codes to run
exactly for 60 seconds
*/
function runFor60seconds(){
/*anyRequestFails takes boolean value and I can easily determine
its value.
*/
if(anyRequestFails){
//stop timer and exit from function
}
// I want to this every 5 secs
else{
//Calculations
let params = calculatedvalue
this.props.callAPI(params)
}
}
}
How can I achieve this? I am learning React and redux and unable to figure it out. The above code snippet is just a pseudocode of my required code.
To use a timer in JavaScript you can use:
setInterval();
In this case you want to assign the interval to a variable so you can cancel it like so;
var minute = 60000;
var myInterval = setInterval(function(){ ... }, minute);
clearInterval(myInterval);
And to keep track of your failed requests you need to assign a variable outside the scope of the function that's calling your api like this;
var failedAmount = 0;
function apiRequest(){
if(failedAmount === 3) clearInterval(myInterval);
...
onFail = () => failedAmount++;
};
For more information on intervals see:
Intervals
Window.setInterval() can be used to create intervals.
Window.clearInterval() can be used to clear intervals.
// Eg.
class Eg extends React.Component {
// Single interval.
singleInterval = () => {
// Prevent duplicates.
clearInterval(this.interval)
// Set timeout.
const fiveSeconds = 1000 * 5
this.timeout = new Date()*1 + fiveSeconds
// Create Interval.
this.interval = setInterval(() => {
// Interval logic ..
console.log('Single Interval: 1 second ..')
if (new Date() > this.timeout) {
// Interval complete.
console.log('Interval complete.')
// Tidy up.
clearInterval(this.interval)
}
}, 1000)
}
// Concurrent interval.
concurrentInterval = () => {
// Set timeout.
const fiveSeconds = 1000 * 5
const timeout = new Date()*1 + fiveSeconds
// Create Interval.
const ID = setInterval(() => {
// Interval logic ..
console.log(`Interval ${ID}`)
if (new Date() > timeout) {
// Interval complete.
console.log(`${ID} complete.`)
// Tidy up.
clearInterval(ID)
}
}, 1000)
}
// Render.
render = () => (
<React.Fragment>
<button onClick={this.singleInterval}>Single Interval</button>
<button onClick={this.concurrentInterval}>Concurrent Interval</button>
</React.Fragment>
)
}
// Mount.
ReactDOM.render(<Eg/>, document.querySelector('#root'))
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>

Javascript - Pausing an IIFE output that has setTimeout and displays min/sec - Pomodoro Clock

I have two functions that display minutes and seconds. Inside the functions I'm using an IIFE with a setTimeout to calculate the time. After getting this, having a hard time figuring out how I could pause the display if pause button is clicked.
The timer works fine and displays correctly.
I realize this is probably not a good way to do it, but I spent so much time (trying to learn how to use IIFE) that I don't want to give up. If I have to, then I will scratch it.
Update - This timer will be getting input from the user. It might be 25 minutes. I want it to start counting down from there until it reaches 0, and the user able to pause at anytime.
let convertToSeconds = document.getElementById('timeValue').value * 60;
let seconds = 60;
function secondsCounter(time) {
// let flag = document.getElementById('pauseButton').value;
for (let i = seconds; i > 0; i--) {
(function(x) {
setTimeout(function() {
let remaining = seconds - x;
document.getElementById('displaySeconds').innerHTML = remaining;
console.log(remaining);
}, i * 1000);
})(i);
}
}
function counter() {
for (let i = convertToSeconds; i > 0; i--) {
(function(minutes) {
setTimeout(function() {
let remaining = Math.floor((convertToSeconds - minutes) / 60);
document.getElementById('displayMinutes').innerHTML = remaining;
console.log(remaining);
}, i * 1000);
setTimeout(function() {
secondsCounter(seconds);
}, i * 60000);
})(i);
}
secondsCounter(seconds);
}
I've tried a couple of things.
Using a flag and if statement around document.getElementById('displaySeconds').innerHTML = remaining; so if my pause button is clicked, the flag changes, and another setTimeout (10 minutes) is triggered. Doesn't stop the countdown on the DOM, it keeps going. I just wanted to see some reaction, but nothing happened. Something like:
function secondsCounter(time) {
let flag = document.getElementById('pauseButton').value;
for (let i = seconds; i > 0; i--) {
(function(x) {
setTimeout(function() {
let remaining = seconds - x;
if (flag === 'yes') {
document.getElementById('displaySeconds').innerHTML = remaining;
console.log(remaining);
} else {
setTimeout(function() {
console.log(remaining);
}, 10000);
}
}, i * 1000);
})(i);
}
}
Using a setInterval and clearInterval that didn't do anything.
Is this possible? Not sure where else to look. Thank you
You can't stop/pause a setTimeout or clearTimeout without making a reference to the timer, storing it and then calling clearTimeout(timer) or clearInterval(timer).
So, instead of: setTimeout(someFunciton)
You need: timer = setTimeout(someFunciton)
And, the timer variable needs to be declared in a scope that is accessible to all functions that will use it.
See setTimeout() for details.
Without a reference to the timer, you will not be able to stop it and that's caused you to go on a wild goose chase for other ways to do it, which is overthinking what you actually need.
In the end, I think you should just have one function that does all the counting down so that you only have one timer to worry about.
Lastly, you can use the JavaScript Date object and its get / set Hours, Minutes and Seconds methods to take care of the reverse counting for you.
(function() {
// Ask user for a time to start counting down from.
var countdown = prompt("How much time do you want to put on the clock? (hh:mm:ss)");
// Take that string and split it into the HH, MM and SS stored in an array
var countdownArray = countdown.split(":")
// Extract the individual pieces of the array and convert to numbers:
var hh = parseInt(countdownArray[0],10);
var mm = parseInt(countdownArray[1],10);
var ss = parseInt(countdownArray[2],10);
// Make a new date and set it to the countdown value
var countdownTime = new Date();
countdownTime.setHours(hh, mm, ss);
// DOM object variables
var clock = null, btnStart = null, btnStop = null;
// Make a reference to the timer that will represent the running clock function
var timer = null;
window.addEventListener("DOMContentLoaded", function () {
// Make a cache variable to the DOM element we'll want to use more than once:
clock = document.getElementById("clock");
btnStart = document.getElementById("btnStart");
btnStop = document.getElementById("btnStop");
// Wire up the buttons
btnStart.addEventListener("click", startClock);
btnStop.addEventListener("click", stopClock);
// Start the clock
startClock();
});
function startClock() {
// Make sure to stop any previously running timers so that only
// one will ever be running
clearTimeout(timer);
// Get the current time and display
console.log(countdownTime.getSeconds());
countdownTime.setSeconds(countdownTime.getSeconds() - 1);
clock.innerHTML = countdownTime.toLocaleTimeString().replace(" AM", "");
// Have this function call itself, recursively every 900ms
timer = setTimeout(startClock, 900);
}
function stopClock() {
// Have this function call itself, recursively every 900ms
clearTimeout(timer);
}
}());
<div id="clock"></div>
<button id="btnStart">Start Clock</button>
<button id="btnStop">Stop Clock</button>

Categories

Resources