trying to call a closure function in javascript - javascript

I have a timer that I want to start by calling
countdownTimer.start(600,'/page2.html');
After showing the timer counting down from 600 seconds, it will redirect to page2.html
I also want to resume a previous timer (from a cookie) by calling the following. I'm just using cookies to save the value where it left off, so if the page is refreshed it will resume counting instead of starting over.
countdownTimer.resume(123, '/page2.html');
I'm getting all kinds of errors, about inner html not being defined (I assume this is related to the variables at the top of the function not being called).
can someone please help me understand how to create javascript objects like this? it has always confused me :/
var countdownTimer = (function() {
var elem = document.getElementById("countdown");
var url = '';
var end = 60;
var _second = 1000;
var _minute = 60000;
var _hour = 3600000;
var timer;
function pad (n, amount) {
return n > parseInt(Array(amount).join("9")) ? "" + n : "0" + n;
}
function showRemaining () {
var now = new Date().getTime();
var distance = end - now;
if (distance < 0 ) {
clearInterval( timer );
elem.innerHTML = "Offer Expired";
window.location.href = url;
return;
}
var minutes = Math.floor( (distance % _hour) / _minute );
var seconds = Math.floor( (distance % _minute) / _second );
var milliseconds = Math.floor( (distance % _second) );
elem.innerHTML = pad(minutes, 2) + ' <span>:</span> ';
elem.innerHTML += pad(seconds, 2) + ' <span>:</span> ';
elem.innerHTML += pad(milliseconds, 3);
}
var start = function (secondsToExpire, url) {
url = url;
end = new Date().getTime() + (secondsToExpire * 1000);
timer = setInterval(showRemaining, 1);
}
var resume = function (customEnd, url) {
url = url;
end = customEnd;
timer = setInterval(showRemaining, 1);
}
var currentTime = function () {
return 500;
}
return {
start: start,
resume: resume,
currentTime: currentTime
};
})();

Related

Can't I run multiple javascript functions with setInterval on a page?

Update
Turns out, coding while tired is not optimal. As pointed out in the comments, I was missing the definition of oneHour in countdownAutoLogout()... It must have been accidentally deleted in the copy & paste-process... Sorry for the inconvenience! I'll show myself out.
I have two almost identical countdown functions located in site.js. One is working, the other not so much.
I used to have only countdownAutoLogout(), and it was working as expected. Upon adding countdownMeeting(durationSeconds), countdownAutoLogout() is only initiated, but doesn't count down, as I have illustrated with the alert()s in the code.
countdownAutoLogout() is called in the <body>-tag in _Layout.cshtml:
<body onload="javascript: countdownAutoLogout();">
countdownMeeting(durationSeconds) is called in the scripts section in the view:
#section scripts{
<script>
$(document).ready(function() {
// Model.RemainingSeconds is a model property of type double.
countdownMeeting(#Model.RemainingSeconds);
})
</script>
}
The functions:
// Padding with leading zero:
function pad(str, max, padder) {
padder = typeof padder === "undefined"
? "0"
: padder;
return str.toString().length < max
? pad(padder.toString() + str, max, padder)
: str;
}
function countdownAutoLogout() {
alert("This alert pops up.");
var oneMinute = 60000;
var twoHours = oneMinute * 121;
var countDownDate = Date.now() + twoHours;
var x = setInterval(function () {
var now = Date.now();
var distance = countDownDate - now;
var hours = Math.floor((distance % (oneHour * 24)) / oneHour);
var minutes = Math.floor((distance % oneHour) / oneMinute);
alert("This alert doesn't pop up.");
document.getElementById("SessionCookieExpirationCountdown").innerHTML =
pad(hours, 2) + ":" + pad(minutes, 2);
if (distance < 0) {
clearInterval(x);
location.href = "/Home/Timeout";
}
}, 5000);
}
// This function is working smoothly:
function countdownMeeting(durationSeconds) {
var oneMinute = 60000;
var oneHour = oneMinute * 60;
var duration = oneMinute * durationSeconds / 60;
var countDownDate = Date.now() + duration;
var x = setInterval(function () {
var now = Date.now();
var distance = countDownDate - now;
var hours = Math.floor((distance % (oneHour * 24)) / oneHour);
var minutes = Math.floor((distance % oneHour) / oneMinute);
var seconds = Math.floor((distance % oneMinute) / 1000);
document.getElementById("MeetingDurationCountdown").innerHTML =
pad(hours, 2) + ":" + pad(minutes, 2) + ":" + pad(seconds, 2);
if (distance < 0) {
clearInterval(x);
document.getElementById("MeetingDurationCountdown").innerHTML = "Overtime!";
}
}, 1000);
}

How can I make this js script so that it doesn't use eval?

I have this code
var clsStopwatch = function() {
var startAt = 0;
var lapTime = 0;
var now = function() {
return (new Date()).getTime();
};
this.start = function() {
startAt = startAt ? startAt : now();
};
this.stop = function() {
lapTime = startAt ? lapTime + now() - startAt : lapTime;
startAt = 0;
};
// Reset
this.reset = function() {
lapTime = startAt = 0;
};
// Duration
this.time = function() {
return lapTime + (startAt ? now() - startAt : 0);
};
};
var x = new clsStopwatch();
var $time;
var clocktimer;
function pad(num, size) {
var s = "0000" + num;
return s.substr(s.length - size);
}
function formatTime(time) {
var h = m = s = ms = 0;
var newTime = '';
h = Math.floor( time / (60 * 60 * 1000) );
time = time % (60 * 60 * 1000);
m = Math.floor( time / (60 * 1000) );
time = time % (60 * 1000);
s = Math.floor( time / 1000 );
ms = time % 1000;
newTime = pad(h, 2) + ':' + pad(m, 2) + ':' + pad(s, 2) + ':' + pad(ms, 3);
return newTime;
}
function show() {
$time = document.getElementById('time');
update();
}
function update() {
$time.innerHTML = formatTime(x.time());
}
function start() {
clocktimer = setInterval("update()", 1);
x.start();
}
function stop() {
x.stop();
clearInterval(clocktimer);
}
function reset() {
stop();
x.reset();
update();
}
Which runs a stopwatch.
My CSP conf has this unsafe-eval directive. It is insecure, so I removed it. And my code won't work and says in the console log that
clocktimer = setInterval("update()", 1);
is not allowed to run. How can I make it so that it can be run without the unsafe-eval directive?
I am unable to know what to do because I am really new to JS.
"update()" is just a string, and can't be called. You need to pass the function.
// Reference the function (probably better)
clocktimer = setInterval(update, 1)
// Call function with lambda (better in some situations, but not this one)
clocktimer = setInterval(() => update(), 1)

How can i reset my countdown and avoid multiple timer

I made a timer countdown in js. It runs after a click event. The issue is when i click again the timer doesn't reset and it creates another countdown but the former one still count. I would like to reset the first when i click again.
i tried to use a clear interval but i'm not sure to use it right.
function countdownto(target, time, callback) {
var finish = new Date(time);
var s = 1000,
m = s * 60,
h = m * 60,
d = h * 24;
(function timer() {
var now = new Date();
var dist = finish - now;
var days = Math.floor(dist / d),
hours = Math.floor((dist % d) / h),
minutes = Math.floor((dist % h) / m),
seconds = Math.floor((dist % m) / s);
var timestring = minutes + ' minute(s) ' + seconds + ' seconde(s)';
target.innerHTML = timestring
if (dist > 0) {
setTimeout(timer, 1000);
} else {
callback()
}
})()
}
var submitBtn = document.getElementById('yes');
submitBtn.addEventListener("click", function(e) {
// countdown element
var countdownel = document.getElementById('clockdiv');
// 20 min
var time = new Date()
time.setSeconds(time.getSeconds() + 1200)
// countdown function call
countdownto(countdownel, time, function() {
alert('end');
})
})
<button id="yes"></button>
<div><span id="clockdiv">countdown
</span></div>
You need to clear the last timeout on each click.
To do that create a global variable and assign the timeout into. After you can use clearTimeout on each click
See live demo
var timeout;
function countdownto(target, time, callback) {
var finish = new Date(time);
var s = 1000,
m = s * 60,
h = m * 60,
d = h * 24;
(function timer() {
var now = new Date();
var dist = finish - now;
var days = Math.floor(dist / d),
hours = Math.floor((dist % d) / h),
minutes = Math.floor((dist % h) / m),
seconds = Math.floor((dist % m) / s);
var timestring = minutes + ' minute(s) ' + seconds + ' seconde(s)';
target.innerHTML = timestring
if (dist > 0) {
timeout = setTimeout(timer, 1000);
} else {
callback()
}
})()
}
var submitBtn = document.getElementById('yes');
submitBtn.addEventListener("click", function(e) {
clearTimeout(timeout)
// countdown element
var countdownel = document.getElementById('clockdiv');
// 20 min
var time = new Date()
time.setSeconds(time.getSeconds() + 1200)
// countdown function call
countdownto(countdownel, time, function() {
alert('end');
})
})
<button id="yes">yes</button>
<div><span id="clockdiv">countdown
</span></div>
Note : You are simulate setInterval with setTimeout. I think it's better to use directly setInterval in your case
setTimeout(timer, 1000) returns internal timer ID. To stop the function you've passed in setTimeout() you have to stop the timer by calling clearTimeout(ID) function and pass internal timer ID you've got from setTimeout()
Also I recommend you to use setInterval():
var myVar = setInterval(myTimer, 1000);
function myTimer() {
var d = new Date();
document.getElementById("demo").innerHTML = d.toLocaleTimeString();
}
to stop myTimer function clear myVar
clearTimeout(myVar);

Convert "stopwatch" time to hourly

I have a stopwatch timer built in JS that counts up from 0 using hours, minutes, seconds and milliseconds. Currently when the user hits the stop button the value from the timer is appended to a hidden input element for form submission. I need to convert whatever the time is to just hourly to where it is appended to that hidden input. So right now if my clock is stopped at 25 minutes and 00 seconds, the value in the input is 00:25:00, I would like it to convert the time to something like .25 (for hours)
For example, for 30 minutes the value appended to my hidden input would be .5, for 45 minutes it would be .75, so on and so fourth.
Here is the stopwatch script, the Stop function is where the value is appended to our hidden input, just need to make sure it is converted to hourly
<script type="text/javascript">
var clsStopwatch = function () {
var startAt = 0;
var lapTime = 0;
var now = function () {
return (new Date()).getTime();
};
this.start = function () {
startAt = startAt ? startAt : now();
};
this.stop = function () {
lapTime = startAt ? lapTime + now() - startAt : lapTime;
startAt = 0;
};
this.time = function () {
return lapTime + (startAt ? now() - startAt : 0);
};
};
var x = new clsStopwatch();
var $time;
var clocktimer;
function pad(num, size) {
var s = "0000" + num;
return s.substr(s.length - size);
}
function formatTime(time) {
var h = m = s = ms = 0;
var newTime = '';
h = Math.floor(time / (3600 * 1000));
time = time % (3600 * 1000);
m = Math.floor(time / (60 * 1000));
time = time % (60 * 1000);
s = Math.floor(time / 1000);
ms = time % 1000;
newTime = pad(h, 2) + ':' + pad(m, 2) + ':' + pad(s, 2);
//newTime = pad(h, 2) + ':' + pad(m, 2) + ':' + pad(s, 2) + ':' + pad(ms, 2);
return newTime;
}
function show() {
$time = document.getElementById('time');
update();
}
function update() {
$time.innerHTML = formatTime(x.time());
}
function start() {
clocktimer = setInterval("update()", 1);
x.start();
}
function stop() {
x.stop();
document.getElementById('counter').value = formatTime(x.time());
clearInterval(clocktimer);
}
</script>
If I correctly understand what you need, this is your solution:
function millisecondsToHours(amountMS) {
return amountMS / 3600000;
}

javascript countdown stutter

I have a countdown like this one:
var countdown = {
startInterval: function() {
var count = 600
var countorig = 600;
var currentId = setInterval(function() {
var min = (count - (count % 60)) / 60;
var sec = count % 60;
if (sec < 10) {
$('#timer').html(min + ':0' + sec);
} else {
$('#timer').html(min + ':' + sec);
}
$('#time').val(countorig - count);
if (count == 0) {
$('#form').submit();
}--count;
}, 1000);
countdown.intervalId = currentId;
}
};
It works. But if I load the page, the countdown starts but it stutter it is not "round" like a clock is.
JSFiddle.
setInterval isn’t exact. You should use Dates instead, to get an accurate time, and then choose an interval of less than one second to get a smoother clock. Here’s a demo!
var countdown = {
startInterval: function() {
var count = 600;
var start = new Date(); // The current date!
var currentId = setInterval(function() {
var difference = Math.max(0, count - (new Date() - start) / 1000 | 0);
var min = difference / 60 | 0;
var sec = difference % 60;
$('#timer').text(min + ':' + (sec < 10 ? '0' : '') + sec);
$('#time').val(difference);
if(count === 0) {
$('#form').submit();
}
}, 200);
countdown.intervalId = currentId;
}
};
It's never a good idea to assume your timers are exact. Instead, use delta timing.
var startTime = new Date().getTime();
setInterval(function() {
var elapsed = new Date().getTime()-startTime;
console.log("Been running for "+Math.floor(elapsed/1000)+" seconds");
},25);
That is because setInterval is not meant to be a high resolution timer. It will NOT hit every 1000 milliseconds on the dot. You might have swings as much as 20 to 30 milliseconds in either direction, resulting in a clock that is off.
Using Date.now(), this is a quick example of a countdown function ( x is milliseconds )
function countdown(x){
var o = {future: Date.now()+x, last:-1, i:null}; // object so we can pass by-ref if req.
o.i = setInterval( function() { // use o.i so we can clear interval
var remain = o.future - Date.now(),
secs = Math.floor( remain / 1000 ),
mins = 0;
if( remain < 0 ){ // finished, do whatever
return clearInterval(o.i); // then clear & exit
}
if( secs === o.last ) return; // skip this iteration if it's not been a second
o.last = secs; // else update last time
// do whatever you want for this new second
if( secs > 59 ) mins = Math.floor( secs / 60 ), secs = secs % 60;
console.log(
(mins < 10 ? '0'+mins : mins) + ':' +
(secs < 10 ? '0'+secs : secs) + ' remain.'
);
}, 100);
}
If you know it wont be used in IE, consider adding o as an argument to the callback function in the interval and also as the last argument to setInterval (so it is passed to the callback as first arg), which means closure is independent => callback can be defined anywhere.

Categories