Timer keeps getting faster on every reset - javascript

The timer keeps getting faster every time I reset it. I'm thinking I need to use clearTimeout but am unsure about how to implement it. Here's the code:
$(function(){
sessionmin = 25;
$("#sessionMinutes").html(sessionmin);
$("#circle").click(function() {
timeInSeconds = sessionmin * 60;
timeout();
});
})
function timeout(){
setTimeout(function () {
if (timeInSeconds > 0) {
timeInSeconds -= 1;
hours = Math.floor(timeInSeconds/3600);
minutes = Math.floor((timeInSeconds - hours*3600)/60);
seconds = Math.floor(timeInSeconds - hours*3600 - minutes*60);
$("#timer").html(hours + ":" + minutes + ":" + seconds);
}
timeout();
}, 1000);
}

You have to define your setTimeout as a variable to reset it.
See Fiddle
var thisTimer; // Variable declaration.
$(function(){
sessionmin = 25;
$("#sessionMinutes").html(sessionmin);
$("#circle").click(function(){
clearTimeout(thisTimer); // Clear previous timeout
timeInSeconds = sessionmin * 60;
timeout();
});
})
function timeout(){
thisTimer = setTimeout(function () { // define a timeout into a variable
if(timeInSeconds>0){
timeInSeconds-=1;
hours = Math.floor(timeInSeconds/3600);
minutes = Math.floor((timeInSeconds - hours)/60);
seconds = (timeInSeconds - hours*3600 - minutes*60)
$("#timer").html(hours + ":" + minutes + ":" + seconds);
}
timeout();
}, 1000);
}

You should: use setInterval instead of setTimeout, return the interval id that setInterval generates, clear that interval before you restart it. Here is an example: https://jsfiddle.net/8n2b7x0s/
$(function(){
var sessionmin = 25;
var intervalId = null;
$("#sessionMinutes").html(sessionmin);
$("#circle").click(function() {
timeInSeconds = sessionmin * 60;
// clear the current interval so your code isn't running multiple times
clearInterval(intervalId);
// restart the timer
intervalId = run();
});
})
function run(){
return setInterval(function () {
if(timeInSeconds>0){
timeInSeconds-=1;
hours = Math.floor(timeInSeconds/3600);
minutes = Math.floor((timeInSeconds - hours)/60);
seconds = (timeInSeconds - hours*3600 - minutes*60)
$("#timer").html(hours + ":" + minutes + ":" + seconds);
}
}, 1000);
}

Related

Stopping timer at end of block using javascript

I am new to this. I have a Qaultrics survey consisting of different blocks; each block with its own timer. What I want to achieve is the following; if participants complete the first block before the given time, the timer on that block will be cleared as they move to the next block where a new timer would start. In the following block, a new timer needs to start.
Any assistance would be greatly appreciated.
Qualtrics.SurveyEngine.addOnload(function()
{
var headerCont = document.createElement("div");
headerCont.className = "header-cont";
headerCont.id = "header_container";
var header = document.createElement("div");
header.className = "header"
header.id = "header_1";
var timer = document.createElement("div");
timer.className = "timer";
timer.id = "timer_1";
timer.innerHTML = "Time Remaining: <span id='time'>01:00</span>";
headerCont.appendChild(header);
header.appendChild(timer);
document.body.insertBefore(headerCont, document.body.firstChild);
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
var myTimer = setInterval(function() {
minutes = parseInt(timer / 60, 10)
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
var text = ('innerText' in display)? 'innerText' : 'textContent';
display[text] = minutes + ":" + seconds;
if (--timer < 0) {
clearInterval(myTimer);
timeOver();
}
}, 1000);
}
var timerSeconds = 60,
display = document.querySelector('#time');
startTimer(timerSeconds, display);
var timeOver = function() {
document.getElementById("timer_1").innerHTML = "";}
});
Qualtrics.SurveyEngine.addOnUnload(function()
{
clearInterval(myTimer);
clearInterval(timer);
clearInterval(timer_1);
document.getElementById("timer_1").innerHTML = "";
});
Here is what I did;
On the first question I used the following code
```Qualtrics.SurveyEngine.addOnload(function()
{
var headerCont = document.createElement("div");
headerCont.className = "header-cont";
headerCont.id = "header_container";
var header = document.createElement("div");
header.className = "header"
header.id = "header_1";
var timer = document.createElement("div");
timer.className = "timer";
timer.id = "timer_1";
timer.innerHTML = "Time Remaining: <span id='time'>02:10</span>";
headerCont.appendChild(header);
header.appendChild(timer);
document.body.insertBefore(headerCont, document.body.firstChild);
function startTimer(duration, display) {
var timer = duration, minutes, seconds;
var myTimer = setInterval(function() {
minutes = parseInt(timer / 60, 10)
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
var text = ('innerText' in display)? 'innerText' : 'textContent';
display[text] = minutes + ":" + seconds;
if (--timer < 0) {
clearInterval(myTimer);
timeOver();
}
}, 1000);
}
var timerSeconds = 130,
display = document.querySelector('#time');
startTimer(timerSeconds, display);
var timeOver = function() {
document.getElementById("timer_1").innerHTML = "";}
});```
Then in the last question in the block, I used the following code
{
Qualtrics.SurveyEngine.addOnPageSubmit(function() {
Qualtrics.SurveyEngine.setEmbeddedData('timeRemaining',timer);
clearInterval(myTimer); // fairly certain this isn't doing anything
});
});
Qualtrics.SurveyEngine.addOnReady(function()
{
/*Place your JavaScript here to run when the page is fully displayed*/
});
Qualtrics.SurveyEngine.addOnUnload(function() {
document.getElementById("header_container").remove();
});```

how to create click event to display set interval time

I have a Javascript setInterval function set up to display like a timer. I'd like to display the time that is on the timer when a "next" button is clicked so the user can see how long they've spent on a certain page. I'm unsure how to connect the setInterval with a click event. This is what I have, but it's not working.
let timerId = setInterval(function () {
document.getElementById("seconds").innerHTML = pad(++sec % 60);
document.getElementById("minutes").innerHTML = pad(parseInt(sec / 60, 10));
}, 1000);
function myFunction() {
alert document.getElementById("timerId").innerHTML = "Time passed: " + timerId);
}
This should solve your problem.
var initialTime = new Date().getTime();
var timeSpent='0:00';
var timeElement = document.getElementById("time");
timeElement.innerHTML = timeSpent;
let timerId = setInterval(function () {
var currentTime = new Date().getTime();
timeSpent = millisToMinutesAndSeconds(currentTime - initialTime)
timeElement.innerHTML = timeSpent;
}, 1000);
function millisToMinutesAndSeconds(millis) {
var minutes = Math.floor(millis / 60000);
var seconds = ((millis % 60000) / 1000).toFixed(0);
return minutes + ":" + (seconds < 10 ? '0' : '') + seconds;
}
function alertFn(){alert(timeSpent)}
document.getElementById("rightButton").addEventListener('click',alertFn);
document.getElementById("wrongButton").addEventListener('click',alertFn);
<h1 id="time"></h1>
<button id="rightButton">Right</button>
<button id="wrongButton">Wrong</button>
First of all, it would be better if you put setInterval method inside the function. After that you could give your function to an event listener as an argument.
Your code should look something like this
let timerId;
function displayTime() {
timerId = setInterval(() => {
// your code
}, 1000);
}
document.querySelector('button').addEventListener('click', displayTime)

Showing multiple timer function in Angular.js

I am trying to display two timer on a webpage with different start times.
First timer only shows for 5 seconds and then after 10 seconds I need to show timer2.
I am very new to Angular and have put together following code.
It seems to be working fine except when the settimeout is called the third time it doesn't work correctly and it starts going very fast.
Controller
// initialise variables
$scope.tickInterval = 1000; //ms
var min ='';
var sec ='';
$scope.ti = 0;
$scope.startTimer1 = function() {
$scope.ti++;
min = (Math.floor($scope.ti/60)<10)?("0" + Math.floor($scope.ti/60)):(Math.floor($scope.ti/60));
sec = $scope.ti%60<10?("0" + $scope.ti%60):($scope.ti%60);
$scope.timer1 = min + ":" + sec;
mytimeout1 = $timeout($scope.startTimer1, $scope.tickInterval); // reset the timer
}
//start timer 1
$scope.startTimer1();
$scope.$watch('timer1',function(){
if($scope.timer1 !=undefined){
if($scope.timer1 =='00:05'){
$timeout.cancel(mytimeout1);
setInterval(function(){
$scope.startTimer2()
$scope.ti = 0;
},1000)
}
}
})
//start timer 2 after 2 mins and 20 seconds
$scope.startTimer2 = function() {
$scope.ti++;
min = (Math.floor($scope.ti/60)<10)?("0" + Math.floor($scope.ti/60)):(Math.floor($scope.ti/60));
sec = $scope.ti%60<10?("0" + $scope.ti%60):($scope.ti%60);
$scope.timer2 = min + ":" + sec;
mytimeout2 = $timeout($scope.startTimer2, $scope.tickInterval);
}
$scope.$watch('timer2',function(){
if($scope.timer2 !=undefined){
if($scope.timer2 =='00:05'){
$timeout.cancel(mytimeout2);
setInterval(function(){
$scope.startTimer1();
$scope.ti = 0;
},1000)
}
}
})
In my view I simply have
<p>{{timer1}}</p>
<p>{{timer2}}</p>
You're basically starting multiple startTimer function so it's adding up. If i understood your problem well you don't even need to have all those watchers and timeouts.
You just can use $interval this way :
$scope.Timer = $interval(function () {
++$scope.tickCount
if ($scope.tickCount <= 5) {
$scope.timer1++
} else {
$scope.timer2++
if ($scope.tickCount >= 10)
$scope.tickCount = 0;
}
}, 1000);
Working fiddle

How can I modify my function to be able to cancel the interval from anywhere in the controller

I am trying to create a countdown and I want to be able to cancel the interval not only when reach 0 but with clicking of a button as well.How can I modify my function to be able to cancel the interval from anywhere in the controller.
function countDown(total) {
total = total * 60;
var interval = $interval(function () {
var minutes = Math.floor(total / 60);
var seconds = total - minutes * 60;
if (minutes < 1)
{
minutes = '0:';
}
else
{
minutes = minutes + ':';
}
if (seconds < 10)
{
seconds = '0' + seconds;
}
self.remainingTime = "Remaining time: " + minutes + seconds;
total--;
if(minutes === '0:' && seconds === '00')
{
$interval.cancel(interval);
}
}, 1000);
}
As suggested by other users, you should make interval global in the controller. Then on the other functions you want to cancel the interval you can call it safely.
Take a look at the below sample:
angular.module('app', [])
.controller('ctrl', function($interval) {
var self = this;
var interval;
self.wizard = {
startInterval: startInterval,
cancelInterval: cancelInterval
};
startInterval();
return self.wizard;
function startInterval() {
countDown(24);
}
function cancelInterval() {
$interval.cancel(interval);
}
function countDown(total) {
cancelInterval();
total = total * 60;
interval = $interval(function() {
var minutes = Math.floor(total / 60);
var seconds = total - minutes * 60;
if (minutes < 1) {
minutes = '0:';
} else {
minutes = minutes + ':';
}
if (seconds < 10) {
seconds = '0' + seconds;
}
self.wizard.remainingTime = "Remaining time: " + minutes + seconds;
total--;
if (minutes === '0:' && seconds === '00') {
$interval.cancel(interval);
}
}, 1000);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<span ng-app="app" ng-controller="ctrl as ctrl">
<span ng-bind="ctrl.remainingTime"> </span>
<br/>
Cancel Interval
<br/>
Start Interval
</span>
I created an example using self instead of $scope like you are in your snippet above. As others mentioned moving the interval var to the global scope fixes this. I also added a stop and start function to test the issue you mentioned in the example above.
UPDATED - I added some code to the stop interval to reset the interval to undefined. I found an example of this usage on Angular's site so it might be worth a try to see if it fixes your other issue.
var app = angular.module('app', []);
app.controller('BaseController', function($interval) {
var self = this;
var interval;
function countDown(total) {
total = total * 60;
interval = $interval(function() {
var minutes = Math.floor(total / 60);
var seconds = total - minutes * 60;
if (minutes < 1) {
minutes = '0:';
} else {
minutes = minutes + ':';
}
if (seconds < 10) {
seconds = '0' + seconds;
}
self.remainingTime = "Remaining time: " + minutes + seconds;
total--;
if (minutes === '0:' && seconds === '00') {
$interval.cancel(interval);
}
}, 1000);
}
self.stopInterval = function(){
if (angular.isDefined(interval)) {
$interval.cancel(interval);
interval = undefined;
}
}
self.startInterval = function(){
countDown(10);
}
});
Then in the html I added a button to start and stop the interval like so:
<body ng-app="app">
<div ng-controller="BaseController as baseCtrl">
{{ baseCtrl.remainingTime }}
<div>
<button ng-click="baseCtrl.startInterval()">Start Countdown</button>
<button ng-click="baseCtrl.stopInterval()">Stop Countdown</button>
</div>
</div>
</body>
You can view the codepen example here

SetInterval not refreshing HTML in Chrome

I'm trying to implement a script that essentially counts down from 30 seconds to 0, and at 0, redirects to the homepage. However, I noticed that my script only works on Firefox but not Chrome and Safari. On these browsers, the counter remains "stuck" at 30 seconds—never refreshing the HTML, but the redirect works fine. Not sure if I'm doing something wrong or if setInterval is not the right method for this kind of thing.
<script>
var seconds = 31;
var counter = setInterval("timer()", 1000);
function timer() {
seconds = seconds - 1;
if (seconds < 0) {
setTimeout("location.href='http://www.homepage.com';", 100);
return;
}
updateTimer();
}
function updateTimer() {
document.getElementById('timer').innerHTML = "Redirecting in " + " " + seconds + " " + "seconds";
}
</script>
Thanks in advance!
EDIT: So weirdly enough, my code (and all of yours) is working on JSFiddle, but it's just failing to "repaint" the HTMLinner when it's actually rendering the page. The seconds are changing fine (I outputted them to the console), the changes just aren't rendering.
Final Edit: This problem basically resulted from invalid CSS. I believe—the counter was running above the photo and I set the span to relative positioning with a higher z-index and top and bottom elements. I don't believe this is acceptable for something that is not a block.
Here's a working sample:
(function() { // wrapper for locals
var timer = document.getElementById("timer"),
seconds = 5,
counter = setInterval(function() {
if (--seconds < 1) {
clearInterval(counter);
timer.innerHTML = "Redirecting now...";
setTimeout(function() {
location.href = 'http://www.homepage.com';
}, 500);
} else {
timer.innerHTML = timer.innerHTML.replace(/\d+/, seconds);
}
}, 1000);
})();
<div id="timer">Redirecting in 5 seconds</div>
​
​
Here is a cleaner implementation with fewer defined functions (with demo):
<span id='timer'></span>
<script>
var seconds = 31;
setInterval(function() {
seconds = seconds - 1;
if (seconds < 0) {
setTimeout(function() {document.getElementById('timer').innerHTML = "redirecting..."}, 100);
return;
}
updateTimer();
}, 1000);
function updateTimer() {
document.getElementById('timer').innerHTML = "Redirecting in " + + seconds + " seconds";
}
<script>
Of course every JavaScript programmer should any opportunity to point out that "eval is evil" which includes passing a string to setInterval and setTimeout :)
Change your function to a variable, that worked for me:
<script>
var seconds = 31;
var counter = setInterval(timer, 1000);
var timer = function() {
seconds = seconds - 1;
if (seconds < 0) {
setTimeout("location.href='http://www.homepage.com';", 100);
return;
}
updateTimer();
}
function updateTimer() {
document.getElementById('timer').innerHTML = "Redirecting in " + " " + seconds + " " + "seconds";
}
</script>

Categories

Resources