timer implementation in javascript - javascript

I had written following code for implementing a timer in JS. But the issue is, for the subsequent recursive calls, the method throws reference error for timeChkSplitTime. How does it happen as its being passed in settimeout().
Also, later I used the easy timer js lib for this. If possible, pls provide an idea to configure the timer for minutes and seconds alone.
function timeChkold(timeChkSplitTime) {
var min = timeChkSplitTime[0], sec = timeChkSplitTime[1];
if (!(timeChkSplitTime[0]==0 && splitTime[1]==0)) {
var strSec, strMin = "0"+min.toString();
if (sec < 10) strSec = "0"+ sec.toString();
else strSec = sec.toString();
$(".timer-btn time").html(strMin+":"+strSec);
timeChkSplitTime[0]=0;
if (sec > 0) timeChkSplitTime[1]--;
else timeChkSplitTime[1] = 59;
setTimeout( "timeChk(timeChkSplitTime);", 1000);
}
else {
var startBtn = $(".start-btn");
startBtn.html("Start");
startBtn.css( {
"border": "1px solid #56B68B",
"background": "#56B68B",
});
var startTime = "01:00";
$(".timer-btn time").html(startTime);
}
}

setTimeout( "timeChk(timeChkSplitTime);", 1000);
should be
setTimeout( timeChk(timeChkSplitTime), 1000);

Variables aren't parsed through strings, on the line with the code:
setTimeout( "timeChk(timeChkSplitTime);", 1000);
It's literally reading the parameter as the value as the text timeChkSplitTime and not the value of the variable timeChkSplitTime. Other than using a string use a function for setTimeout:
setTimeout( timeChk(timeChkSplitTime), 1000);

your code is a little bit of a spaghetti code. you should seperate your code logic from the view. split them into functions. and most importantly, using setTimeout is not efficient in this case.
var CountdownTimer = function(startTime) {
var timeInSeconds = this.stringToSeconds(startTime);
this.original = timeInSeconds;
this.time = timeInSeconds;
this.running = false;
}
CountdownTimer.prototype.start = function(callback) {
this.running = true;
this.interval = setInterval(function() {
if(this.time < 1) {
this.running = false;
clearInterval(this.interval);
} else {
this.time -= 1;
callback();
}
}.bind(this), 1000);
}
CountdownTimer.prototype.pause = function() {
if(this.running) {
this.running = false;
clearInterval(this.interval);
}
}
CountdownTimer.prototype.restart = function() {
this.time = this.original;
}
CountdownTimer.prototype.stringToSeconds = function(timeSting) {
var timeArray = timeSting.split(':');
var minutes = parseInt(timeArray[0], 10);
var seconds = parseInt(timeArray[1], 10);
var totalSeconds = (minutes*60) + seconds;
return totalSeconds;
}
CountdownTimer.prototype.secondsToStrings = function(timeNumber) {
finalString = '';
var minutes = parseInt(timeNumber/60, 10);
var seconds = timeNumber - (minutes*60);
var minStr = String(minutes);
var secStr = String(seconds);
if(minutes < 10) minStr = "0" + minStr;
if(seconds < 10) secStr = "0" + secStr;
return minStr + ":" + secStr;
}
to run this code you can add the following
var countdownTest = new CountdownTimer("01:15");
countdownTest.start(onEachTick);
function onEachTick() {
var time = countdownTest.secondsToStrings(countdownTest.time);
console.log(time)
}
you can write your custom code in the onEachTick funciton.
you can check if the timer is running by typing countdownTest.running.
you can also restart and pause the timer. now you can customize your views however you want.

Related

I can't call a class function inside another class function in Javascript

I want to call the function "displayTime" in "startTimer" but for some reason I get "Uncaught TypeError: this.displayTime is not a function" in the console.
let endTimer = "0";
let isRunning = false;
//! CLASS
class Timer {
constructor(endTimer, isRunning) {
this.endTimer = endTimer;
this.isRunning = isRunning;
}
startTimer() {
if (this.endTimer === "0") {
this.endTimer = new Date().getTime() + 1500000;
}
displayTime();
if (this.isRunning === true) {
this.pauseTimer();
this.isRunning
}
this.isRunning = true;
}
displayTime() {
let now = new Date().getTime();
let remainingTime = this.endTimer - now;
let minutes = Math.floor(remainingTime / 1000 / 60);
let seconds = Math.floor((remainingTime / 1000) % 60);
if (seconds < 10) {
seconds = "0" + seconds;
}
timer.innerHTML = `<h1>${minutes}:${seconds}</h1>`;
start.textContent = "STOP"
this.update = setInterval(this.displayTime, 100);
}
}
let newTimer = new Timer(endTimer, isRunning);
//! EVENT LISTENERS
start.addEventListener("click", newTimer.startTimer);
I think that I'm missing something obvious, but I don't understand what...
start.addEventListener("click", newTimer.startTimer.bind(newTimer));
Calling displayTime(); without the prepended keyword 'this' is the main issue (line 16 below) as mentioned by GenericUser and Heretic Monkey in the comments above.
You probably already know this but you'll want to define a pauseTimer() method/function as well.
let endTimer = "0";
let isRunning = false;
//! CLASS
class Timer {
constructor(endTimer, isRunning) {
this.endTimer = endTimer;
this.isRunning = isRunning;
}
}
Timer.prototype.startTimer = function() {
if (this.endTimer === "0") {
this.endTimer = new Date().getTime() + 1500000;
}
this.displayTime(); // this is the important line
if (this.isRunning === true) {
this.pauseTimer();
this.isRunning
}
this.isRunning = true;
}
Timer.prototype.displayTime = function() {
let now = new Date().getTime();
let remainingTime = this.endTimer - now;
let minutes = Math.floor(remainingTime / 1000 / 60);
let seconds = Math.floor((remainingTime / 1000) % 60);
if (seconds < 10) {
seconds = "0" + seconds;
}
//timer.innerHTML = `<h1>${minutes}:${seconds}</h1>`;
//start.textContent = "STOP"
this.update = setInterval(this.displayTime, 100);
}
Timer.prototype.pauseTimer = function() {
this.isRunning = false;
}
let newTimer = new Timer("0", true);
newTimer.startTimer();
//! EVENT LISTENERS
//start.addEventListener("click", newTimer.startTimer);
class Timer {
startTimer() {
// You forgot this keyword
this.displayTime();
}
displayTime() {
console.log('do something');
}
}
let newTimer = new Timer();
// addEventListener changes the context of this.
// Using an arrow function will keep 'this' keyword in tact inside startTimer method
start.addEventListener('click', () => newTimer.startTimer)

In Javascript, I'm using clearInterval() in a function/reset button - the timer resets, but keeps going

I've made a timer with setInterval():
var seconds = 0, minutes = 0;
var timer = document.querySelector("#timer");
var interval = null;
function beginTimer() {
var interval = setInterval(function(){
timer.innerHTML = minutes + " Minute(s) " + seconds + " Seconds";
seconds++;
if(seconds == 60) {
minutes++;
seconds = 0;
}
else if(minutes == 60) {
return "Out of time!";
}
}, 1000);
}
I've set a button in HTML to reset it, but when I use it to clear the timer, it continues running. This is the function with the clearInterval() in it.
function beginGame() {
cards = shuffle(cards);
for (var n = 0; n < cards.length; n++) {
allCards.innerHTML = "";
[].forEach.call(cards, function(item) {
allCards.appendChild(item);
});
cards[n].classList.remove("match", "open", "disable", "show");
}
//resetting values
moves = 0;
counter.innerHTML = moves;
star1.style.visibility = "visible";
star2.style.visibility = "visible";
star3.style.visibility = "visible";
lemon.style.visibility = "hidden";
seconds = 0;
minutes = 0;
clearInterval(interval);
var timer = document.querySelector("#timer");
timer.innerHTML = "0 Minute(s) 0 Seconds";
}
I've been researching this for a couple of days with no luck... could someone kindly help me understand how to stop the timer from continuing to run after reset is initialized? Thanks.
Because you have var interval inside beginTimer, the interval variable inside beginTimer will always reference the local variable, which is distinct from the outer interval (which is never touched). Once beginTimer ends, the local interval variable will simply be garbage collected. Leave off the var to assign to the outer variable instead:
var interval = null;
function beginTimer() {
interval = setInterval(function(){
var intervalinside the beginTimer() is error.
var seconds = 0, minutes = 0;
var timer = document.querySelector("#timer");
var interval = null;
function beginTimer() {
// var interval = setInterval(function(){
interval = setInterval(function(){
timer.innerHTML = minutes + " Minute(s) " + seconds + " Seconds";
seconds++;
if(seconds == 60) {
minutes++;
seconds = 0;
}
else if(minutes == 60) {
return "Out of time!";
}
}, 1000);
}
You need also to reset the ongoing timer before starting a new one. Please try the following:
var interval;
function beginTimer() {
clearInterval(interval);
interval = setInterval(function(){
...

trying to create timer for quiz

var myVar = setInterval(function() {
myTimer()
}, 1000);
var d = 1;
function myTimer() {
document.getElementById("demo").innerHTML = d++;
}
Can any one help me how to set the dynamic timer in JavaScript?
I'm trying to create a quiz application and I need to run a timer for the questions which is already available in the database.
I have to retrieve a time from the database and I have to run a count-down timer.
What about something like this. It doesn't reply on the timer being perfect.
var running = false;
var timeToRun = 10000; // 10 seconds
var startTime;
var timer;
var output = document.getElementById("output");
function start(){
running = true;
startTime = new Date();
timer = setInterval(check, 100);
output.innerHTML = "Started<br>" + output.innerHTML;
}
function stop(){
running = false;
clearInterval(timer);
}
function check(){
var now = new Date();
var left = (startTime - now) + timeToRun;
output.innerHTML = left + "<br>" + output.innerHTML;
if (left < 0){
stop();
output.innerHTML = "times up <br>" + output.innerHTML;
}
}
start();
<div id="output">o</div>
function myTimer(d) {
d++;
document.getElementById("demo").innerHTML = d;
return d;
}
var d = 1;
var myVar = setInterval(function() {
d = myTimer(d);
}, 1000);
like this?
[Edit after reading comments:]
var endpoint = [php_timestamp_here];
var countdown = setInterval(function() {
var d = new Date();
var ts = d.getTime();
if( ts >= endpoint ){
// stuff after reach the point...
clearInterval(countdown);
}
// stuff every second
}, 1000);

Stop and run again timer via pure javascript

I want to make a simple countdown timer which can be set by + or - and also it can be stopped and run by clicking on itself.
My problem is when it is stopped and then runs it shows NAN for the first number.
I suppose it is because of setTimer function but I don't know how to fix that.Here is my code:
var x = document.getElementsByClassName('session');
var seconds = 60;
var session;
var t;
var on = true;
var minutes = 1;
for (var i = 0; i < x.length; i++) {
x[i].innerHTML = minutes;
}
function increase() {
minutes++;
for (var i = 0; i < x.length; i++) {
x[i].innerHTML = minutes;
}
}
function decrease() {
minutes--;
for (var i = 0; i < x.length; i++) {
if (x[i].innerHTML > 0) {
x[i].innerHTML = minutes;
}
}
}
function setSession() {
session = x[1].innerHTML - 1;
}
function timer() {
if (seconds > 0) {
seconds--;
if (seconds == 0 && session > 0) {
session--;
seconds = 60;
}
}
x[1].innerHTML = session + ':' + seconds;
}
function stoptimer() {
clearInterval(t);
}
function general() {
if (on) {
on = false;
t = setInterval(timer, 100);
} else {
on = true;
stoptimer();
}
}
<div class='session'></div>
<div id='increase' onclick='decrease()'>-</div>
<div id='increase' onclick='increase()'>+</div>
<div class='session' onclick='setSession();general()'></div>
You shouldn't be setting session from the html entity. Basically this creates issues with parsing and could potentially break your code. Also, you subtract one every time you get this value, throwing a spanner in the works.
I re-shuffled your code a bit and added some notes, take a look:
var x = document.getElementsByClassName('session');
var seconds = 0;
var session;
var timer; // give this a useful name
var timerRunning = false; // give this a useful name
var minutes = 1;
function updateMinutes(newMinutes){
if (timerRunning){
return; // do not allow updating of countdown while count down is running
}
if(newMinutes !== undefined){ // allow this function to be called without any parameters
minutes = newMinutes;
}
if(minutes < 1){
minutes = 1; //set your minimum allowed value
}
if(minutes > 99999){
minutes = 99999; //could also have some sort of maximum;
}
for (var i = 0; i < x.length; i++) {
x[i].innerHTML = minutes;
}
session = minutes; // now this can only be set while timer is not running, so no need to get it from the html
//also, i would let this start at the exact same value as minutes, and have seconds start at zero
}
updateMinutes(); // call this now to initialise the display
function increase() {
updateMinutes(minutes + 1);
}
function decrease() {
updateMinutes(minutes - 1);
}
function timer_tick() {
if (seconds > 0) {
seconds--;
if (seconds == -1 && session > 0) { //because of where you've positioned your logic, this should check for negative one, no zero, otherwise you'll never display a zero seconds value
session--;
seconds = 59; //when a timer clocks over it goes to 59
}
}
if (session > 0 || seconds > 0){
x[1].innerHTML = session + ':' + seconds;
}
else{// you need to detect the ending
x[1].innerHTML = "Finished!!";
}
}
function timer_stop() {
clearInterval(timer);
}
function timer_start(){
timer = setInterval(timer_tick, 1000);
}
function timer_toggle() { //give these timer functions consistent names
if (!timerRunning) {
timer_start();
} else {
timer_stop();
}
timerRunning = !timerRunning; //just flip the boolean
}
You set
x[1].innerHTML = session + ':' + seconds;
and then try to calculate that as
session = x[1].innerHTML - 1;
You need to either put the session:seconds in another place or do
session = parseInt(x[1].innerHTML,10) - 1;
Ok, I would propose another approach. Use a class for your timer, like this:
function MyTimer(htmlEl) {
this.sec = 0;
this.min = 0;
this.elt = htmlEl;
}
MyTimer.prototype.set = function(m) {
this.min = m;
this.display();
var self = this;
this._dec = function() {
self.sec--;
if (self.sec < 0) {
if (self.min == 0) {
self.stop();
} else {
self.min -= 1;
self.sec = 59;
}
}
self.display();
}
}
MyTimer.prototype.display = function() {
this.elt.innerHTML = this.min + ":" + this.sec;
}
MyTimer.prototype.toggle = function() {
if (this.interval) {
this.stop();
this.interval = undefined;
} else this.start();
}
MyTimer.prototype.start = function() {
this.interval = setInterval(this._dec, 100);
};
MyTimer.prototype.stop = function() {
clearInterval(this.interval);
};
Then, you can use it like this:
window.onload = init;
var minutes, x, timer;
function init() {
x = document.getElementsByClassName('session');
timer = new MyTimer(x[1]);
minutes = 0;
}
function increase() {
minutes += 1;
x[0].innerHTML = minutes;
timer.set(minutes);
}
function decrease() {
minutes -= 1;
x[0].innerHTML = minutes;
timer.set(minutes);
}
function general() {
timer.toggle();
}
The only change in your html is to remove the setSession call:
<div id='timer' onclick='general()'></div>
This code is more clear. You encapsulate the logic and the min/sec in an object, which is reusable. Here is a working fiddle : https://jsfiddle.net/Shitsu/zs7osc59/.
The origin of your problem is in the code
session = x[1].innerHTML - 1;
Let's re-visit the purpose of keeping of the variable 'session'. I guess it is to keep the value of the maximum value, the upper limit of the minutes, from where to start counting, right? On the other hand, the 'minutes' variable is to keep the temporary value of the minutes. What confused you here is that you've used 'minutes' in place of it's upper limit (what actually is the session's role), in this code for example
function increase() {
minutes++;
for (var i = 0; i < x.length; i++) {
x[i].innerHTML = minutes;
}
}
see, you are updating html by the value of 'minutes', and later you are reading that value into 'session' by that evil code:
session = x[1].innerHTML - 1;
So, why? Why you need to update the value of 'your' variable from html? You should only update the html according to the value of session var and not vice versa. Let's go on and make life simpler...
Let's keep the temporary value of minutes in 'minutes', let's also keep the upper limit in a variable session and, please, let's rename it to maxMinutes. Let's update the 'maxMinutes' only when user clicks '+' or '-' (NEVER from html).
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
</head>
<body>
<script>
var x = document.getElementsByClassName('session');
var maxMinutes = 0;
var minutes = maxMinutes;
var seconds = 0;
var timer;
var on = false;
function increase() {
if(on) {
return;
}
maxMinutes++;
minutes = maxMinutes;
x[0].innerHTML = maxMinutes;
x[1].innerHTML = minutes;
}
function decrease() {
if(on) {
return;
}
if(maxMinutes == 0)
{
return;
}
maxMinutes--;
minutes=maxMinutes;
x[0].innerHTML = maxMinutes;
x[1].innerHTML = minutes;
}
function periodicRun() {
if (seconds > 0) {
seconds--;
}
else if(seconds == 0)
{
if(minutes > 0) {
minutes--;
seconds = 60;
}
else
{
stopTimer(timer);
return;
}
}
x[1].innerHTML = minutes + ':' + seconds;
}
function stoptimer() {
clearInterval(timer);
}
function general() {
if (on) {
on = false;
stoptimer();
} else {
on = true;
timer = setInterval(periodicRun, 500);
}
}
$(document).ready(function(){
increase();
});
</script>
<div class='session'></div>
<div id='increase' onclick='decrease()'>-</div>
<div id='increase' onclick='increase()'>+</div>
<div class='session' onclick='general()'></div>
</body>
</html>
Note, that the only place where the maxLimits get's assigned a value is in increase() and decrease(). The 'minutes' and html are in their turn being updated according to maxMinutes.
Good Luck!

Cant a function be implemented into while loop?

function start() {
var work = document.getElementById("work").value;
var rest = document.getElementById("rest").value;
var rounds = document.getElementById("rounds");
var timer = document.getElementById("timer");
function countdown() {
var roundsValue = rounds.value;
while (roundsValue > 0) {
var worktime = setInterval(function () {
timer.value = work + "sec";
work = work - 1;
if (work === 0) {
clearInterval(worktime);
}
}, 1000);
var resttime = setInterval(function(){
timer.value = rest + "sec";
rest = rest-1;
if(rest === 0){
clearInterval(resttime);
}
}, 1000);
roundsValue = roundsValue-1;
}
}
}
I am working on my javascript progress right now and I came here with this problem. I want to repeat the same amount of work time and rest time as rounds are but it doesnt work like this and I cant help myself. For example: 8 rounds of 10 seconds of work and then 5seconds of rest. It maybe doesnt work because function cant be implemented into a WHILE loop.
fiddle: http://jsfiddle.net/shhyq02e/4/
Here is a quick fix, may not be the best way to go about it but will get what to do.
http://jsfiddle.net/sahilbatla/shhyq02e/6/
function start() {
var rounds = document.getElementById("rounds");
var timer = document.getElementById("timer");
var roundsValue = parseInt(rounds.value);
(function countdown() {
var work = document.getElementById("work").value;
var rest = document.getElementById("rest").value;
if (roundsValue > 0) {
var worktime = setInterval(function () {
timer.value = work + "sec(work)";
work = work - 1;
if (work === 0) {
clearInterval(worktime);
var resttime = setInterval(function() {
timer.value = rest + "sec(rest)";
rest = rest - 1;
if (rest === 0) {
clearInterval(resttime);
--roundsValue;
countdown();
}
}, 1000);
}
}, 1000);
}
})();
}

Categories

Resources