Javascript clearInterval is speeding up a timer instead of pausing it - javascript

I've got a ColdFusion application that I am developing that requires a timer that can start, pause, and clear. My problem is that although it works perfectly fine in IE9, Firefox, Opera, Chrome, and Safari, it will not work in IE8 (which is a huge chunk of my userbase). The issue is that when I click and try to stop the timer, instead of the timer stopping, it speeds up. It only does it in IE8 (the other browsers work fine).
-- CLOCK CODE --
function check_timer() {
if($('#timer').hasClass('start')) {
$('#timer').val("Stop Timer");
timer = setInterval ( "increaseCounter()", 1000 );
$('#timer').removeClass('start')
}
else {
if(typeof timer != "undefined") {
clearInterval(timer);
}
$('#timer').val("Start Timer");
$('#timer').addClass('start')
}
}
function increaseCounter() {
var secVal;
var minVal;
secVal = parseInt($('#counterSec').html(),10)
minVal = parseInt($('#counterMin').html(),10)
if(secVal != 59) {
secVal = secVal + 1;
if(secVal < 10) {
secVal = secVal.toString();
secVal = "0" + secVal;
}
$('#counterSec').html(secVal);
}
else {
if(minVal != 59){
minVal = minVal + 1;
if(minVal < 10) {
minVal = minVal.toString();
minVal = "0" + minVal;
}
$('#counterMin').html(minVal);
}
else {
$('#counterHour').html((parseInt($('#counterHour').html(),10)+1));
$('#counterMin').html("00");
}
$('#counterSec').html("00");
}
}
-- DIV CONTAINING CLOCK --
<div class="supportClock" style="width:150px; border-radius:20px;" align="center">
<span id="addZeroHour"></span>
<span id="counterHour">00</span>
:<span id="addZeroMin"></span>
<span id="counterMin">00</span>
:<span id="addZeroSec"></span>
<span id="counterSec">00</span>
</div>
-- BUTTON TO ACTIVATE CLOCK --
<input type="button" id="timer" class="start" value="Start Timer" onclick="check_timer()">

add this to the top of your script(outside the functions):
var timer;
Otherwise you will never run into this branch:
if(typeof timer != "undefined")
The reason: there is an element with the ID "timer", you may access it by using timer without the suggested modification and timer will never be of type "undefined"
Or simply use another name for the timeout-variable.

Have a look here: http://jsfiddle.net/qEATW/3/
Even if you set an interval to be, for example, one second, it won't necessarily be one second between calls.
For timeouts and intervals, always pass in the function, never a string: setInterval(increaseCounter, 1000)
There's no reason to parse values from the DOM. It's incredibly inefficient to do so. If you instead use Date differences, you can simply store one variable (start time), and get hours/mins/seconds since that time. You can update the view however often you like and it will always be accurate.
I personally prefer "recursive" timeouts as opposed to intervals. With intervals, you'll always need to take that extra step to clear the interval when you want it to stop. You can stop a timeout loop in several different ways, and it tends to be easier to understand what's going on. Timeouts also allow us the flexibility of changing the time between calls (not that that is relevant here).
It is considered a bad practice to bind event handlers inline (on the HTML element). If you are already using jQuery, there's really no excuse for this as jQuery makes the process so very simple.
I got rid of the "addZero" spans that you had. I'm not sure what you were doing with them, but they weren't necessary and only served to clutter the markup.
HTML:
<div class="supportClock" style="width:150px; border-radius:20px;" align="center">
<span id="counterHour">00</span>
: <span id="counterMin">00</span>
: <span id="counterSec">00</span>
</div>
<input type="button" id="timer" class="start" value="Start Timer">
JS:
(function(){
var clock = $(".supportClock"),
hr = $("#counterHour"),
min = $("#counterMin"),
sec = $("#counterSec"),
running = false,
startTime,
timeout;
function updateClock(){
var time = (new Date()) - startTime,
hrs = Math.floor(time / 1000 / 60 / 60),
mins = Math.floor(time / 1000 / 60 - hrs * 60),
secs = Math.floor(time / 1000 - mins * 60 - hrs * 60 * 60);
hr.text(hrs > 9 ? hrs : '0' + hrs);
min.text(mins > 9 ? mins: '0' + mins);
sec.text(secs > 9 ? secs : '0' + secs);
timeout = setTimeout(updateClock, 1000/2);
}
$("#timer").click(function(){
if (!running){
running = true;
this.value = "Stop Timer";
startTime = new Date();
updateClock();
}
else{
running = false;
this.value = "Start Timer";
clearTimeout(timeout);
}
});
})();

Related

Simple javascript counter that can be paused and resumed after web page has been closed

I need to create a very simple Javascript-based counter, which counts currency (so two decimal places) and increases in value by 0.18 every minute. The idea is to represent "live" estimated savings by the company's new solar panels, and this counter will be started and stopped by an employee every day, to continue the next day.
I found a fiddle by somebody else for a start/resume counter: http://jsfiddle.net/f9X6J/
HTML:
<span id="hour"></span>
<span id="min"></span>
<span id="sec"></span>
<input id="pauseButton" type="button" value="Pause">
<input id="resumeButton" type="button" value="Resume">
Javascript:
var Clock = {
totalSeconds: 1000,
start: function () {
var self = this;
this.interval = setInterval(function () {
self.totalSeconds += 1;
$("#hour").text(Math.floor(self.totalSeconds / 3600));
$("#min").text(Math.floor(self.totalSeconds / 60 % 60));
$("#sec").text(parseInt(self.totalSeconds % 60));
}, 1000);
},
pause: function () {
clearInterval(this.interval);
delete this.interval;
},
resume: function () {
if (!this.interval) this.start();
}
};
Clock.start();
$('#pauseButton').click(function () { Clock.pause(); });
$('#resumeButton').click(function () { Clock.resume(); });
This is great so far, but I please need the following:
It must not calculate time, but rather money.
It must be saved to the server in case the computer shuts off.
Thanks!
For the sake of beginners in 2019. The answer to the two questions are,
1) Keep a counter outside the clock object and keep adding 1 to it every second the clock is active. This will give the total number of seconds the clock has been active. This can be then converted to total savings at any point.
2) Don't jump on to server side stuff just yet. Try to store the total with localStorage which persists even if the computer is switched off until browsing data is cleared in the browser. This will avoid lot of added complexity. An example for storing values locally and reading from them is below.
<html>
<head></head>
<body>
<div id="counter"></div>
</body>
<script>
var counter;
if( localStorage.getItem("counter") == null) {
counter = 0;
localStorage.setItem("counter", counter);
} else {
counter = localStorage.getItem("counter");
}
document.getElementById('counter').textContent = counter;
setInterval(function(){
counter = parseInt(counter)+1;
localStorage.setItem("counter", counter);
document.getElementById('counter').textContent = counter;
},1000);
</script>
</html>
Hope this provides a right direction.

How to stop resetting a JavaScript timer while refreshing the page

I am doing an online examination page. In this page I have a countdown timer that counts down by a value from the database. It's working fine but when I refresh the page it resets. I have to stop the timer from resetting.
Here is my JavaScript timer code:
<script type="text/javascript">
function CountDown(duration, display) {
if (!isNaN(duration)) {
var timer = duration, minutes, seconds;
var interVal = setInterval(function () {
minutes = parseInt(timer / 60, 10);
seconds = parseInt(timer % 60, 10);
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
$(display).html("<b>" +"Time Remaining: "+ minutes + "m : " + seconds + "s" + "</b>");
if (--timer < 0) {
timer = duration;
SubmitFunction();
$('#display').empty();
clearInterval(interVal)
}
},1000);
}
}
function SubmitFunction(){
$('#result').click();
}
CountDown(<?php echo $t*30; ?>,$('#display')); //$t comes from database
function disable_f5(e) {
if ((e.which || e.keyCode) == 116) {
e.preventDefault();
}
}
$(document).ready(function(){
$(document).bind("keydown", disable_f5);
});
</script>
I just saw your question and am going to take a crack at it. One thing that I recommend is trying to commit the values to local storage. You could add an event listener, have it specify to listen for a reload, and on that reload commit the integer value to local storage in JSON format. Just an idea.
If you are using a db already, what about adding a table or an extra field to an existing table that registers the datetime that the user commenced the examination and then on each page load - you can get the commencement time from the db, do some funky calculations and then display the remaining time.
That way you are not relying on the calculation in browser keeping track (although I would probably try session storage for it as already suggested), but a constant start time that you can confidently calculate from.
try this as an approach - note only skeleton of code listed to demonstrate approach. I would personally set the datetime in the db though.
//at commencement of exam
//js var commencementTime = (//calculation to get current time);
localStorage.setItem('commencementTime ',commencementTime );
//on page reload
var commencementTime= localStorage.getItem('commencementTime ');
if(commencementTime){
//code for calculating countdown}

How can I build a secure timer based button?

here's what I mean:
I have written up a simple timer that counts down from 5 minutes. At the end of 5 minutes, I'd like to display a button for my user to press. You can see my code at the end of this post.
I do not want the user to be able to press see the button before the timer runs out. I don't want the user to be able to go into the JS console and call "document.getElementById("button").style.display = 'block';" and have access to the button.
What are some ways I can do this, preferably entirely on the client side? Is there a way to do this entirely on the client side?
My backend is Ruby on Rails - if there's an easy solution using RoR, I'd be curious about that too. But frankly, I'd love to know if there's a fully client side way of doing this!
<html>
<script>
function startTimer(duration, display) {
var start = Date.now(),
diff,
minutes,
seconds;
function timer(timerIntervalId) {
diff = duration - (((Date.now() - start) / 1000) | 0);
minutes = (diff / 60) | 0;
seconds = (diff % 60) | 0;
minutes = minutes < 10 ? "0" + minutes : minutes;
seconds = seconds < 10 ? "0" + seconds : seconds;
display.textContent = minutes + ":" + seconds;
if (minutes == "00" && seconds == "00" && timerIntervalId != undefined) {
clearInterval(timerIntervalId);
document.getElementById("button").style.display = 'block';
}
if (diff <= 0) {
start = Date.now() + 1000;
}
};
timer();
var timerIntervalId = setInterval(function() { timer(timerIntervalId) }, 1000);
}
window.onload = function () {
var timerLength = 60 * .15,
display = document.querySelector('#time');
startTimer(timerLength, display);
};
</script>
<body>
<div>Registration closes in <span id="time"></span> minutes!</div>
<div id = "button" style = "display: none;">BUTTON</div>
</body>
</html>
I hate to say it bud, but there is no such thing as secure in javascript. A user with a little knowledge will be able to do anything they want to your code. But to attempt to give a suggestions
if (minutes == "00" && seconds == "00" && timerIntervalId != undefined) {
clearInterval(timerIntervalId);
///document.getElementById("button").style.display = 'block';
$("<div>").attr('id', 'button').appendTo($("#placeholder")).text("button")
}
<body>
<div>Registration closes in <span id="time"></span> minutes!</div>
<div id="placeholder">
</div>
</body>
</html>
this way the button doesnt exist until you create it at the end of the timer
https://jsfiddle.net/u3bae0uj/
There is no fully client side solution. Because if yo implement this fully using client side, user can at some way change the timer (as you said, show button).
To be sure that 5 minutes will pass you will have to communicate with server, but can implement this using ajax.
At timer start you can call some action at server and start timer on server side, using sessions variable, when 5 minutes pass you execute ajax call on other action an check if 5 minutes have pass (this way you get 5 minutes, and user can not change it on client).
If 5 minutes have passed, you return html to user, inside html you return the button you want to show, so user can not inspect html, and set it visible, because server returns button after 5 minutes, and then user can click on it.

Simple countdown using minutes and seconds

I need a countdown that will refresh a page, and I think I've finally got it, except for one thing. I'd like the countdown to be in minutes and seconds, not just seconds (the countdown is for one hour). A simple MM:SS format would be fine, but also writing out minutes and seconds would work. Can anybody help?
<SCRIPT LANGUAGE="JavaScript">
<!--
var counterobj = document.all ? counter : document.getElementById("counter");
var countdownfrom = 3600; //countdown period in seconds
var currentsecond = counterobj.innerHTML = countdownfrom+1;
function countdown()
{
if (currentsecond!=1)
{
currentsecond-=1;
counterobj.innerHTML = currentsecond;
}
else
{
self.location.reload();
return;
}
setTimeout("countdown()",1000)
}
countdown()
//-->
</script>
Calculate minutes using a floor doing like
minute = Math.floor(currentsecond/60);
Then just output as normal.
edit -- fixed! Hopefully! (accidentally said to use mod -- you need to use Floor, I believe)

Strange problem with JavaScript code

Hi Masters Of Web Development,
first I want to say that I did not believe in my eyes - I've got a piece of javascript that works just fine in IE7, and don't in Firefox!!! :)))) That was little joke. :)
So I already told you the problem (it wasn't joke), now I'm pasting the javascript:
<script type="text/javascript">
<!-- This script and many more are available free online at -->
<!-- The JavaScript Source!! http://javascript.internet.com -->
<!-- Begin
var ms;
ms = %%CONTENT_REFRESH%% - 5;
var stop;
stop = 0;
var myvalue;
function display() {
if (!stop) {
setTimeout("display();", 1000);
}
thetime.value = myvalue;
}
function recalc() {
var hours;
var minutes;
var seconds;
ms = ms - 1;
hours = Math.floor(ms / 3600);
minutes = Math.floor(ms / 60);
if (minutes < 10) {
minutes = "0"+minutes;
}
seconds = ms - (minutes*60) - (hours*3600);
if (seconds < 10) {
seconds = "0"+seconds;
}
myvalue = hours+":"+minutes+":"+seconds;
thetime.value = myvalue;
if (myvalue == "0:00:00") {
stop = 1;
}
if (!stop) {
setTimeout("recalc();", 1000);
}
}
// End -->
</SCRIPT>
This is very old script I know that. It takes my current remaining song time, from my winamp and countdowns in site. But as I said, it does not work in Firefox.
Body and code that calls countdown timer looks like this:
<body class="playlist_body" onLoad="recalc();display();">
Time Left In Song: <INPUT align="center" TYPE="text" Name="thetime" size=5 />
</body>
//Edit: I look at FireBug, and I saw the following error:
thetime is not defined
recalc()playlist.cgi (line 87)
function onload(event) { recalc(); display(); }(load )1 (line 2)
error source line: [Break on this error] thetime.value = myvalue;\n
The problem is that it's accessing DOM elements by name.
Add the following code to the top to declare a variable for the thetime element, add id="thetime" to the INPUT, and add a call to init(); in onload in the body element.
var thetime;
function init() {
thetime = document.getElementById('thetime');
}
By the way, you can replace the textbox with a regular DIV element by setting the div's ID to thetime, and replacing thetime.value with thetime.innerHTML.
Also, it's better to call setTimeout with a function instead of a string; you should replace "display();" and "recalc();" with display and recalc respectively.
IE has a "feature" where an element with a name attribute is placed in the window object, eg.
<div name=foo></div>
Will give you a variable "foo" -- this is non-standard, you should do
document.getElementByName("foo")
To get the timer output element.
var thetime = document.getElementById("thetime");
and add id="thetime" instead of just name="thetime" to the input

Categories