jQuery countdown running when it's paused - javascript

I'm using Keith Wood's jQuery Countdown timer. http://keith-wood.name/countdown.html
What I want to achieve is a countup with stop and resume buttons, and controls to add and subtract minutes and seconds:
I create a countup (from 0 to 60 minutes) and pause it right away, like this:
$('#contador_tiempo').countdown({
since: 0,
format: 'MS',
layout: '{mnn}{sep}{snn}'
});
$('#contador_tiempo').countdown('pause');
But it seems that it's still running in the background. When I click the buttons to add or subtract, the functions do the operations on top of that background counter, not the displayed counter.
Full code on JSFiddle, with the behaviour reproduced:
http://jsfiddle.net/J2XHm/4/
(Play a bit with the controls and you will see that it keeps counting although it's paused.)

Yes, there is a bug in the 'getTimes' command - it recalculates when paused. I'll make the correction in the next release (1.6.2) but in the meantime you can change the _getTimesPlugin function:
_getTimesPlugin: function(target) {
var inst = $.data(target, this.propertyName);
return (!inst ? null : (inst._hold == 'pause' ? inst._savePeriods : (!inst._hold ? inst._periods :
this._calculatePeriods(inst, inst._show, inst.options.significant, new Date()))));
},

If you can accept lightweight code, i.e. without using the jQuery countdown timer, the following might help you:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="http://localhost/web/JavaScript/jQuery/jquery"></script>
<script type="text/javascript">
var countUpSeconds = 0;
var interval = null;
function displayTime() {
$("#timeContainer").text(format(Math.floor(countUpSeconds/60))+":"+format(countUpSeconds%60));
}
function playStop() {
if(interval) {interval=window.clearInterval(interval);}
else {interval = window.setInterval(countUp, 1000);}
}
function countUp() {
++countUpSeconds;
if(countUpSeconds >= 3600) {/* do something when countup is reached*/}
displayTime();
}
function format(s) {return s<10 ? "0"+s : s;}
$(function() {
displayTime();
$("#playStop").on("click", function () { playStop(); } );
$("#addMin").on("click", function () { countUpSeconds += 60; displayTime(); } );
$("#subMin").on("click", function () { countUpSeconds = Math.max(0, countUpSeconds-60); displayTime(); } );
$("#addSec").on("click", function () { countUpSeconds += 1; displayTime(); } );
$("#subSec").on("click", function () { countUpSeconds = Math.max(0, countUpSeconds-1); displayTime(); } );
});
</script>
</head>
<body>
<div id="timeContainer"></div>
<button id="playStop">Play/Stop</button>
<button id="addMin">+1 minute</button>
<button id="subMin">-1 minute</button>
<button id="addSec">+1 second</button>
<button id="subSec">-1 second</button>
</body>
</html>

Related

Timer will not fire "onclick". Fires on page load

I am trying to teach myself to code. I am coding a simple quiz. I would like my timer to fire on "start", and eventually, "next question". My timer starts once the page loads. Not sure why.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<button id="b1">Click Me!</button>
<p id="demo"></p>
<script>
var sec = 5;
var time = setInterval(myTimer, 1000);
function myTimer() {
document.getElementById("b1").onclick = function() {
myTimer()
};
document.getElementById('demo').innerHTML = sec + "sec.";
sec--;
if (sec <= -1) {
clearInterval(time);
// alert("Time out!! :(");
document.getElementById("demo").innerHTML="Time's up!";
}
}
Have tried several different ways, including "addEventListener". Nothing seems to work.
If you take a look at a minimal example you'll see that this also runs as soon as the page is loaded. Here setInterval() is called when the script loads in the page. In turn the run() function is called every second.
var timerID = setInterval(run, 1000);
function run() {
console.log("I'm running");
}
Think of the difference between var timer = run; and var timer = run(). The first assigns the function run to timer. The later executes run() and assigns the return value.
Here's your code with comments:
var sec = 5;
// start interval timer and assign the return value "intervalID" to time
var time = setInterval(myTimer, 1000);
// to be called every second
function myTimer() {
// assign an onclick handler to "b1" EVERY SECOND!
document.getElementById("b1").onclick = function() {
myTimer()
};
// update the demo DOM element with sec
document.getElementById('demo').innerHTML = sec + "sec.";
sec--;
if (sec <= -1) {
clearInterval(time);
// alert("Time out!! :(");
document.getElementById("demo").innerHTML="Time's up!";
}
}
For a solution I've moved setInterval into the onclick handler and moved said handler assignment out of the myTimer function as you only want to setup your handlers once.
I've also renamed time to timerID to make it clear what it is.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<button id="b1">Click Me!</button>
<p id="demo"></p>
<script>
var sec = 5;
var timerID;
document.getElementById("b1").onclick = function() {
timerID = setInterval(myTimer, 1000);
};
function myTimer() {
document.getElementById('demo').innerHTML = sec + "sec.";
sec--;
if (sec <= -1) {
clearInterval(timerID);
// alert("Time out!! :(");
document.getElementById("demo").innerHTML="Time's up!";
}
}
</script>
</body>
</html>
I would suggest a couple of extra exercises to help you:
Reset the timer so that you can click on the button to start the timer again
Prevent the timer being started again (which would run multiple timers with different IDs) while a timer is running
The myTimer() function is never invoked. Even if you invoke it, it does not take any action. It's just repeating itself on click.
So, instead of:
function myTimer() {
document.getElementById("b1").onclick = function() {
myTimer()
};
Try adding an Event Listener:
document.getElementById("b1").addEventListener('click', function() {
// inside here you put the code for going into next question
})
Or use just the same code, but not inside a function, and its content to be a meaningful code that leads to the next answer:
document.getElementById("b1").onclick = function() {
// code to proceed into next question
}

how to use time intervals in the function?

I want the letters 'q' to be written only once per second.
But it doubles every second.
How to do this with this command?
function writeNow() {
document.write('q');
setInterval(writeNow, 1000);
}
writeNow();
You can use setTimeout
function writeNow() {
document.write('q');
setTimeout(writeNow, 1000);
}
writeNow();
Or setInterval
function writeNow() {
document.write('q');
}
setInterval(() => {
writeNow()
}, 1000);
You want to set the interval outside the function, when you call it inside the function, it will be recursive
Try
function writeNow() {
document.write('q');
}
setInterval(writeNow, 1000);
writeNow();
And I highly recommend against document.write as it is deprecated
But it doubles every second
Because you are calling the setInterval inside the method. So it looks like recursion
Solution:
You should move setInterval(writeNow, 1000); outside the called function - writeNow.
Syntax
setInterval(function, milliseconds, [param1, param2, ...])
function writeNow() {
document.write('q');
}
setInterval(writeNow, 1000);
Try this
<script>
function writeNow() {
document.write('this');
}
setInterval(writeNow, 1000);
</script>
You were calling a function recursively
The below code does the job. May be able to fine tune a bit to improve performance:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title></title>
<style media="screen">
#letters
{
padding: 10px;
margin: 10px;
}
</style>
</head>
<body>
<div id="letters">
</div>
</body>
<script type="text/javascript">
let alphabets = [];
let running = false;
let output = "";
function prepare()
{
for(i=65; i<92; i++)
{
console.log(String.fromCharCode(i));
alphabets.push(String.fromCharCode(i));
}
}
let lastPrinted = 0;
function printAlphabet()
{
if(lastPrinted == 0)
{
running = true;
}
else if(lastPrinted == 26)
{
running = false;
}
if(running)
{
output += (alphabets[lastPrinted]) + ","
document.getElementById('letters').innerHTML = output;
lastPrinted ++;
setTimeout(printAlphabet, 1000);
}
else
{
output = output.substring(0,output.length - 1)+".";
document.getElementById('letters').innerHTML = output;
}
}
prepare();
printAlphabet();
</script>
</html>
Output:
A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z

Javascript: Automatically clicking a button when countdown is complete

I am trying to display the alert message when the countdown is complete, I am trying the following code but its does not work please help!
<!DOCTYPE html>
<html>
<body>
<p id=count></p>
<form>
<button id="autoClickBtn" onclick="autoClick()">Click me</button>
</form>
<script>
function autoClick(){alert("I am loaded and automatically clicked");}
var count = 5;
var interval = setInterval(function () {
document.getElementById('count').innerHTML = count;
count--;
if (count === -1) {
clearInterval(interval);
window.onload = function () { document.getElementById("autoClickBtn").click() };
}
}, 1000 );
</script>
</body>
</html>
If you want to alert once after a certain time. Use setTimeout function. You can add the delay in milliseconds. In the example below I have added a delay of 2 secs.
setInterval, on the other hand, will run indefinitely again and again after time period defined
setTimeout(function () {
window.alert('This is an alert');
}, 2000);

angular timer - .stop() and .resume() problems

I'm having a bit trouble with my timer. I might have made it more complicated than it should be because what I need is the following:
I need to count from 00:00 to say 45:00 and I need to be able to stop and resume the timer within these boundaries.
Right now I've got this timer code:
<timer id="timer" autostart="false" start-time="coutingStart" end-time="countingEnd">{{mminutes}}:{{sseconds}}</timer>
countingStart and countingEnd initializes like this:
var time = (45 * 60000); // should give me 45 minutes of time.
$scope.countingStart = (new Date()).getTime();
$scope.countingEnd = (new Date()).getTime() + time;
This code above works, atleast I think it does.
I've got a button with this function on it:
$scope.startGame = function() {
$scope.gameIsLive = true;
document.getElementById('timer').start();
};
which starts my counter, no problem, it starts from 00:00 atleast.
But then I have buttons with these functions aswell which is where I'm having my problem.
$scope.PauseGame = function() {
switch ($scope.periodNum) {
case 1:
document.getElementById('timer').stop();
$scope.PauseIsActive = true;
break;
case 2:
document.getElementById('timer').stop();
$scope.PauseIsActive = true;
break;
}
};
$scope.ResumeGame = function() {
switch ($scope.periodNum) {
case 1:
document.getElementById('timer').resume();
$scope.PauseIsActive = false;
break;
case 2:
document.getElementById('timer').resume();
$scope.PauseIsActive = false;
break;
}
};
Both pauseGame() and resumeGame() works as expected. They are pausing and resuming the timer. But, when I pause the timer on say 00:10 and count for myself 10 seconds and then resume it the timer now stands on 00:20 which made me just lost 10 seconds of the timer.
I can think that my problem is inside the instantiating of $scope.counterStart and $scope.counterEnd. But I am not sure. How can I count from 00:00 to 45:00 and still being able to stop and resume the clock when needed?
Angular timer uses the Date object and milliseconds to count time so I suppose I have to use this approach to get 00:00 which is now and count 45 minutes forward. Can it be done otherwise with stop and resume functionality?
Thanks.
If I understand the angular-timer docs end-time sets the countdown time. It doesn't provide a maximum value.
end-time Sets the countdown based on predefined end time (in
milliseconds).
To have a maximum value you can check each tick event to see if the configured maximum value has been reached. I have created an example below in which the timer is stopped when it reaches the maximum value (10 seconds).
(function() {
angular
.module('exampleApp', ['timer'])
.controller('ExampleController', ExampleController);
function ExampleController($scope, TimerStatusEnum, $timeout) {
var vm = this;
vm.max = 10000; // 10 seconds
vm.isMaxReached = false;
vm.timerStatus = TimerStatusEnum.NotStarted;
vm.startTimer = function() {
if (!vm.isMaxReached) {
if (vm.timerStatus === TimerStatusEnum.NotStarted) {
$scope.$broadcast('timer-start');
vm.timerStatus = TimerStatusEnum.Running
} else if (vm.timerStatus === TimerStatusEnum.Stopped) {
$scope.$broadcast('timer-resume');
vm.timerStatus = TimerStatusEnum.Running
}
}
};
vm.stopTimer = function() {
if (vm.timerStatus === TimerStatusEnum.Running) {
$scope.$broadcast('timer-stop');
vm.timerStatus = TimerStatusEnum.Stopped
}
};
vm.isTimerStopped = function() {
return vm.timerStatus === TimerStatusEnum.Stopped;
}
vm.isTimerRunning = function() {
return vm.timerStatus === TimerStatusEnum.Running;
}
$scope.$on('timer-tick', function(event, args) {
var roundedMiliSecondCount = Math.round(args.millis / 1000) * 1000;
if (roundedMiliSecondCount === vm.max) {
$timeout(function() {
vm.isMaxReached = true;
vm.stopTimer();
}, 0);
}
});
}
ExampleController.$inject = ['$scope', 'TimerStatusEnum', '$timeout'];
})();
(function() {
angular
.module('exampleApp')
.constant('TimerStatusEnum', {
'NotStarted': 0,
'Stopped': 1,
'Running': 2
});
})();
<!DOCTYPE html>
<html ng-app='exampleApp'>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-timer/1.3.4/angular-timer.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/humanize-duration/3.9.1/humanize-duration.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.14.1/moment.min.js"></script>
</head>
<body ng-controller="ExampleController as vm">
<timer id="timer" autostart="false" interval="1000">{{mminutes}}:{{sseconds}}</timer>
<button ng-click="vm.startTimer()" ng-disabled="vm.isTimerRunning() || vm.isMaxReached">Start Timer</button>
<button ng-click="vm.stopTimer()" ng-disabled="vm.isTimerStopped() || vm.isMaxReached">Stop Timer</button>
<p ng-if="vm.isMaxReached">Max time has been reached</p>
</body>
</html>

Problems with running 2 JavaScript "onload" functions

I have two JavaScript "onload" functions that I am trying to run on a webpage: a visual timer and a auto refresh function. I have implemented both in my webpage but although the timer runs, the Auto Refresh function will not run unless I remove the visual timer function from the script.
Here is the code for the webpage:
<!DOCTYPE html>
<HTML>
<HEAD>
<script type="text/JavaScript">
<!--
function timedRefresh(timeoutPeriod) {
setTimeout("location.reload(true);",timeoutPeriod);
}
// -->
</script>
<TITLE>test</TITLE>
</head>
<body onload="JavaScript:timedRefresh(15000); timedText();">
<script>
window.onload = timedText;
function timedText() {
var txt = document.getElementById('txt'),
counter = 15;
var timer = setInterval(function () {
if(counter === 0) return clearInterval(timer);
txt.value = counter + " seconds";
counter--;
}, 1000);
}
</script>
<input type="text" id="txt" />
</body></HTML>
Any help in solving this problem would be greatly appreciated.
try with a small change:call timedRefresh() inside window.onload's timetext() function not in body onload.
<!DOCTYPE html>
<HTML>
<HEAD>
<script type="text/JavaScript">
<!--
function timedRefresh(timeoutPeriod) {
setTimeout("location.reload(true);",timeoutPeriod);
}
// -->
</script>
<TITLE>test</TITLE>
</head>
<body>
<script>
window.onload = timedText;
function timedText() {
var txt = document.getElementById('txt'),
counter = 15;
timedRefresh(15000);
var timer = setInterval(function () {
if(counter === 0) return clearInterval(timer);
txt.value = counter + " seconds";
counter--;
}, 1000);
}
</script>
<input type="text" id="txt" />
</body></HTML>
The problem is the second one overrides the first. That is what you should be using addEventListener to add events.
window.addEventListener('load', timedText, false);
window.addEventListener('load', function(){timedRefresh(15000);}, false);
and if you need to support older IEs you need to look at attachEvent
BUT looking at the code why are you running two setTimeouts when all you need to do is when it hits zero call the redirect.
You can add multiple onload events using the addEventListener method, like so:
window.addEventListener("load", timedText, false);
window.addEventListener("load", timedRefresh(15000), false);
function timedText() {
var txt = document.getElementById('txt'),
counter = 15;
var timer = setInterval(function() {
if (counter === 0) return clearInterval(timer);
txt.value = counter + " seconds";
counter--;
}, 1000);
}
function timedRefresh(timeoutPeriod) {
setTimeout("location.reload(true);",
timeoutPeriod);
}
You can find out more information about addEventListener here.
Here's a working codepen.

Categories