Clear interval inside object method - javascript

This code is part of a game where the user has a certain amount of time to input an answer.
I want to be able to clear the interval from outside of the object if the user decides to submit an answer before the allotted time has elapsed.
I have tried returning the interval with an ID so that I can call it later and whilst this does allow me to clear it from outside the outside the object, it means that the code inside the interval function is never run.
const clock = {
timer: 30,
countdown() {
let interval = setInterval(function () {
selectors.timerDisplay.textContent = clock.timer
clock.timer--
if (clock.timer < 0) {
clearInterval(interval)
selectors.wordSubmit.click();
}
}, 1000)
},
}
I appreciate I may have simply set myself up badly to clear this interval, therefore any suggestions on how I could improve it would be appreciated.
Thanks in advance.

You can use Arrow functions to leverage the context of this from your object clock
Add a method i.e clear.
Use this context to reference your inner attributes.
const clock = {
timer: 3,
interval: 0,
reset() {
this.timer = 3;
this.interval = 0;
},
clear() {
clearInterval(this.interval);
this.reset();
},
countdown() {
this.interval = setInterval(() => {
//selectors.timerDisplay.textContent = clock.timer
this.timer--;
console.log(this.timer)
if (this.timer < 0) {
clearInterval(this.interval)
//selectors.wordSubmit.click();
}
}, 1000);
},
}
clock.countdown();
setTimeout(function() {
clock.clear();
}, 1500)
See? the interval function ends after 1.5secs

You can expose a method to clear the interval
const selectors = document.querySelector('div');
const clearTimer = document.querySelector('button');
const clock = {
timer: 5,
// Initiate the interval
int: null,
// This exposes a way to clear the interval outside of the object
clearTimer() {
clearInterval(this.int);
},
countdown() {
// This is where you define this.int
this.int = setInterval(() => {
//selectors.timerDisplay.textContent = clock.timer
selectors.innerText = clock.timer.toString();
clock.timer--
console.log(clock.timer);
if (clock.timer < 0) {
this.clearTimer();
//selectors.wordSubmit.click();
}
}, 1000)
},
}
clock.countdown();
clearTimer.addEventListener('click', () => {
clock.clearTimer();
})
<div>clock.timer</div>
<button>clear timer</button>

As has been suggested in the comments, simply return the interval so it can be stopped later. For example
countdown() {
let interval = setInterval(function () {
selectors.timerDisplay.textContent = clock.timer
clock.timer--
if (clock.timer < 0) {
clearInterval(interval)
selectors.wordSubmit.click();
}
}, 1000)
return interval // added this line
},
Then, consumers can cancel the interval when they want
const interval = clock.countdown()
// and later...
clearInterval(interval)

Related

VueJS how to watch a value and animate when it changes

In my vuejs-application I want to animate a number/value when it changes. The value is based on a response from the vuex-store.
so I've got the animation running, but for some reason the animation loop is infinite and just continues all the time.
data() {
return {
interval: false,
hitsCount: 0
}
},
watch: {
hitsCount: function() {
clearInterval(this.interval);
this.interval = window.setInterval( function() {
let change = this.hitsCount / 10;
change = change >= 0 ? Math.ceil(change) : Math.floor(change);
this.hitsCount = this.hitsCount + change;
}.bind(this),20);
}
}
the template is simply:
<div> {{hitsCount}} </div>
The value hitsCount comes from a request:
this.$store.dispatch("store/data", {}).then(response => {
this.hitsCount = response.total;
.../
});
the value changes each time there is a new request.
As mentioned before, the animation starts right away and keeps counting endlessly - what am I missing here?
Anyway, it's not good idea to watch property you are changing.
Divide it into two variables.
data() {
return {
hitsCount: 0,
hitsCountDisplay: 0
}
},
watch: {
hitsCount() {
clearInterval(this.interval);
if (this.hitsCount !== this.hitsCountDisplay) {
let value = this.hitsCountDisplay;
const change = (this.hitsCount - this.hitsCountDisplay) / 30;
this.interval = setInterval(() => {
value += change;
this.hitsCountDisplay = Math.round(value);
if (this.hitsCountDisplay === this.hitsCount) {
clearInterval(this.interval);
}
}, 20);
}
}
}
and
<div> {{hitsCountDisplay}} </div>
Here is a working example: https://jsfiddle.net/knvyrx8j/
You shouldn't update a property inside its watcher, this will cause an infinite loop, but you could run the animation inside the callback of your action dispatcher :
this.$store.dispatch("store/data", {}).then(response => {
let count = response.total;
clearInterval(this.interval);
this.interval = window.setInterval( function() {
let change = count / 10;
change = change >= 0 ? Math.ceil(change) : Math.floor(change);
this.hitsCount = this.hitsCount + change;
}.bind(this),20);
});

Set up a pause/resume-able timer in javascript

Is there a way to create a "timer"(or stopwatch) class, that the timers created using this class can be paused and resumed on triggering an event, e.g. clicking a button?
I tried to create the class and create timer objects using it, but the timer cannot be paused once it starts.
My attempt on creating this class:
class countdown {
constructor(min, sec) {
this.mins = min;
this.secs = sec;
this.handler = 0;
}
static setTimer(x,minfield,secfield) {
this.handler = setTimeout(() => {
if (x.mins == 0 && x.secs == 0) {
clearTimeout();
} else {
if (x.secs == 0) {
x.mins -= 1;
x.secs = 59;
} else {
x.secs -= 1;
}
}
this.updateTimer(x,minfield,secfield);
this.setTimer(x,minfield,secfield)
}, 1000)
}
static updateTimer(x,minfield, secfield){
document.getElementById(minfield).innerHTML = x.mins;
document.getElementById(secfield).innerHTML = x.secs;
}
static stopTimer(x,minfield,secfield) {
// document.getElementById(minfield).innerHTML = x.mins;
// document.getElementById(secfield).innerHTML = x.secs;
clearTimeout(x.handler);
}
}
Usage:
let countdown1 = new countdown(15,0);
let countdown_act = false;
document.getElementById('button').addEventListener( 'click', () => {
if (!countdown_act) {
countdown.setTimer(countdown1, 'ctdwn-mins', 'ctdwn-secs');
countdown_act = true;
} else {
countdown.stopTimer(countdown1, 'ctdwn-mins', 'ctdwn-secs');
countdown_act = false;
}
console.log(countdown_act);
}
)
The countdown_act flag is used for indicating the state of the timer.
There's no need for any of your methods to be static. Also, it's much simpler and easier to use if you just record seconds and then calculate minutes when you need the output. As a standard, capitalize the name of classes. Finally, you're probably looking for setInterval, not timeout.
Think of a real-world timer. You can set it, start it, pause it, and stop it. Stopping a timer is really just restarting it and pausing it, and it's set upon creation, so let's make a Timer with start, pause, set and stop or reset. This still behaves the same way as yours in the background by using a 1s timeout, but it's a lot cleaner and easier for someone reading your code to understand:
class Timer {
constructor(seconds, callback) {
this.originalTime = seconds;
this.remainingTime = seconds;
this.timeout = null;
this.callback = callback; // This is what the timer does when it ends
}
start() {
this.timeout = setInterval(() => {
this.remainingTime -= 1; // Remove a second from the timer
if(this.remainingTime === 0) {
this.callback(); // Run the callback function
this.stop(); // Stop the timer to prevent it from counting into the negatives
}
}, 1000);
}
pause() {
clearInterval(this.timeout);
}
stop() {
this.pause();
this.remainingTime = this.originalTime; // Reset the time
}
setTime(seconds) {
this.originalTime = seconds; // Set a new time
this.stop(); // Have to restart the timer to account for the new time
}
get remaining() {
return {
seconds: this.remainingTime % 60,
minutes: Math.floor(this.remainingTime / 60)
}
}
}

How to make a countdown timer function reusable

I have a countdown function like the following:
data(){
return {
timer: null
}
}
methods: {
countdown: function(time){
const TIME_COUNT = time;
if (!this.timer) {
this.count = TIME_COUNT;
this.timer = setInterval(() => {
if (this.count > 0 && this.count <= TIME_COUNT) {
this.count--;
}
else{
clearInterval(this.timer);
this.timer = null;
}
}, 1000);
}
I want to call the countdown function with different parameters like countdown(10) or countdown(60) so that every time I call this function it starts counting from the time I want. If I call the countdown method it will count to 0 before the second countdown works. What should I do to make it reusable?
This should let you instantiate multiple countdown instance functions.
const methods = {
countdown: (time) => {
let timeRemaining = time;
let timer;
timer = setInterval(() => {
if (timeRemaining > 0) {
timeRemaining--;
} else {
clearInterval(timer);
}
}, 1000)
}
}

javascript autoreload in infinite loop with time left till next reload

i need a JavaScript, that relaods a page every 30 seconds, and will show how much time there is until next reload at the ID time-to-update, Example:
<p>Refreshing in <span id="time-to-update" class="light-blue"></span> seconds.</p>
i also need it to repeat itself infinitely.
thank you for reading, i hope it helps not me but everyone else, and a real big thank you if you could make this script.
(function() {
var el = document.getElementById('time-to-update');
var count = 30;
setInterval(function() {
count -= 1;
el.innerHTML = count;
if (count == 0) {
location.reload();
}
}, 1000);
})();
A variation that uses setTimeout rather than setInterval, and uses the more cross-browser secure document.location.reload(true);.
var timer = 30;
var el = document.getElementById('time-to-update');
(function loop(el) {
if (timer > 0) {
el.innerHTML = timer;
timer -= 1;
setTimeout(function () { loop(el); }, 1000);
} else {
document.location.reload(true);
}
}(el));
http://jsfiddle.net/zGGEH/1/
var timer = {
interval: null,
seconds: 30,
start: function () {
var self = this,
el = document.getElementById('time-to-update');
el.innerText = this.seconds; // Output initial value
this.interval = setInterval(function () {
self.seconds--;
if (self.seconds == 0)
window.location.reload();
el.innerText = self.seconds;
}, 1000);
},
stop: function () {
window.clearInterval(this.interval)
}
}
timer.start();

How do I reset the setInterval timer?

How do I reset a setInterval timer back to 0?
var myTimer = setInterval(function() {
console.log('idle');
}, 4000);
I tried clearInterval(myTimer) but that completely stops the interval. I want it to restart from 0.
If by "restart", you mean to start a new 4 second interval at this moment, then you must stop and restart the timer.
function myFn() {console.log('idle');}
var myTimer = setInterval(myFn, 4000);
// Then, later at some future time,
// to restart a new 4 second interval starting at this exact moment in time
clearInterval(myTimer);
myTimer = setInterval(myFn, 4000);
You could also use a little timer object that offers a reset feature:
function Timer(fn, t) {
var timerObj = setInterval(fn, t);
this.stop = function() {
if (timerObj) {
clearInterval(timerObj);
timerObj = null;
}
return this;
}
// start timer using current settings (if it's not already running)
this.start = function() {
if (!timerObj) {
this.stop();
timerObj = setInterval(fn, t);
}
return this;
}
// start with new or original interval, stop current interval
this.reset = function(newT = t) {
t = newT;
return this.stop().start();
}
}
Usage:
var timer = new Timer(function() {
// your function here
}, 5000);
// switch interval to 10 seconds
timer.reset(10000);
// stop the timer
timer.stop();
// start the timer
timer.start();
Working demo: https://jsfiddle.net/jfriend00/t17vz506/
Once you clear the interval using clearInterval you could setInterval once again. And to avoid repeating the callback externalize it as a separate function:
var ticker = function() {
console.log('idle');
};
then:
var myTimer = window.setInterval(ticker, 4000);
then when you decide to restart:
window.clearInterval(myTimer);
myTimer = window.setInterval(ticker, 4000);
Here's Typescript and Nuxt 3 version if anyone's interested :]
Composable useInterval.ts
useInterval.ts
export function useInterval (callback: CallableFunction, interval: number): Interval { // Argument interval = milliseconds
return new Interval(callback, interval)
}
class Interval {
private timer = null
constructor (private callback, private interval) {
}
start () {
this.timer = setInterval(this.callback, this.interval)
}
stop () {
clearInterval(this.timer)
this.timer = null
}
restart (interval = 0) {
this.stop()
if (interval) {
this.interval = interval
}
this.start()
}
}
Example usage
const interval = useInterval(function() {
// your function here
}, 5000);
// Reset the interval and set it to 10s
interval.reset(10000);
// Stop the interval
interval.stop();
// Start the interval
interval.start();

Categories

Resources