Why can't I change this global variable from function? (JavaScript) - javascript

Simple countdown project.
Desired outcome:
global variable determines default time.
then slider value overrides that variable.
PROBLEM: slider value changes locally but global value stays the same.
I've watched tutorials all day on variable scopes and still don't see what's wrong because:
Global is declared with "var" outside function: var initialMinutes = 5
attempt to update value inside function looks like this:
const change = slider.addEventListener('change', setMins)
function setMins() {
initialMinutes = slider.value
}
I have also tried with window.variable here and there to no avail.
I hope someone can help. This is becoming difficult to scope with.
const countdown = document.getElementById('countdown')
const slider = document.getElementById('slider')
const startBtn = document.getElementById('btn-startStop')
const resetBtn = document.getElementById('btn-reset')
// Event Listeners
const change = slider.addEventListener('change', setMins)
const start = startBtn.addEventListener('click', startStop)
const reset = resetBtn.addEventListener('click', resetApp)
// Time
var initialMinutes = 15
countdown.innerHTML = initialMinutes+':00'
const initialDuration = initialMinutes * 60
let time = initialMinutes * 60
let interval = null
let status = 'stopped'
function updateCountdown() {
const minutes = Math.floor(time / 60)
let seconds = time % 60
seconds = seconds < 10 ? '0'+ seconds : seconds
if( time < 1) {
clearInterval(interval)
startBtn.innerHTML = 'START'
status = 'stopped'
countdown.innerHTML = `00:00`
} else {
countdown.innerHTML = `${minutes}:${seconds}`
time--;
}
}
function startStop() {
if(status === 'stopped') {
interval = setInterval(updateCountdown, 50)
startBtn.innerHTML = 'STOP'
status = 'running'
} else {
clearInterval(interval)
startBtn.innerHTML = 'START'
status = 'stopped'
}
}
function setMins() {
initialMinutes = slider.value
countdown.innerHTML = slider.value+':00'
}
function resetApp() {
clearInterval(interval);
document.getElementById('countdown').innerHTML = '00:00'
startBtn.innerHTML = 'START'
status = 'stopped'
}
Codepen link included for clarity:
https://codepen.io/donseverino/pen/YzWBJYV

Got it! It was not a problem of scope but of variable assignment.
updateCountdown() uses time and time = initialMinutes * 60
I thought changing initialMinutes would automatically change its value inside time but it doesn't.
Reassigning time inside the function solves it.
function setMins() {
initialMinutes = slider.value
time = initialMinutes * 60
}

Related

How does one refactor best this timer/stopwatch code-base towards a better code-reuse following the OOP paradigm and the DRY principle?

I am having trouble with following OOP in javascript.
How can I make this code more Object-oriented and reusable?
I tried reading up on OOP concepts in JS but couldn't figure a way around making this code be one. Any suggestions?
PS: This is the code for making a stopwatch
//Define variables to hold time values
let seconds = 0;
let minutes = 0;
let hours = 0;
//Define variable to hold "display" value
let interval = null;
//Define variable to hold the clock status
let status = "paused";
//Clock function ( logic to determine when to increment next value, etc.)
function clock() {
seconds++;
//Logic to determine when to increment next value
if (seconds >= 60) {
seconds = 0;
minutes++;
if (minutes >= 60) {
minutes = 0;
hours++;
}
}
//Display updated time values to user
document.getElementById("display").innerHTML =
//If seconds/minutes/hours are only one digit, add a leading 0 to the value
`${hours ? (hours > 9 ? hours : `0${hours}`) : "00"}:${minutes ? (minutes > 9 ? minutes : `0${minutes}`) : "00"}:${seconds > 9 ? seconds : `0${seconds}`}`;
}
function startPause() {
if (status === "paused") {
//Start the stopwatch (by calling the setInterval() function)
interval = window.setInterval(clock, 1000);
document.getElementById("startPause").innerHTML = "Pause";
status = "started";
} else {
window.clearInterval(interval);
document.getElementById("startPause").innerHTML = "Resume";
status = "paused";
}
}
//Function to reset the stopwatch
function reset() {
seconds = 0;
minutes = 0;
hours = 0;
document.getElementById("display").innerHTML = "00:00:00";
document.getElementById("startPause").innerHTML = "Start";
window.clearInterval(interval);
status = "paused";
}
One could use kind of a "component based" approach. The provided example code is pretty straightforward. The constructor does assign all the needed references as public properties to a Stopwatch instance. Getters and setters for reading and writing the component's UI(/DOM) part are implemented as prototypal methods. Helper methods (interval handling, time measure computations) do not need to be part of the class implementation itself, but will be residents of the Stopwatch module scope ...
// module scope of e.g. 'Stopwatch.js' file.
const MEASURE_STATE_RUNNING = 'running';
const MEASURE_STATE_STOPPED = 'stopped';
const UPDATE_CYCLE_MINIMUM = 100; // any value in msec.
const UPDATE_CYCLE_DEFAULT = 200; //
const UPDATE_CYCLE_MAXIMUM = 1000; //
function getDisplayNumber(value) {
return ((String(value).length === 1) && `0${ value }`) || value;
}
function getMeasureInMilliseconds(measure) {
return (((measure.hours * 3600) + (measure.minutes * 60) + measure.seconds) * 1000);
}
function getMeasureFromMilliseconds(value) {
let hours = (value / 3600000);
let minutes = ((hours - Math.floor(hours)) * 60);
let seconds = ((minutes - Math.floor(minutes)) * 60);
hours = Math.floor(hours);
minutes = Math.floor(minutes);
seconds = Math.floor(seconds + 0.001);
seconds = ((seconds < 60) && seconds) || 0;
minutes = ((minutes < 60) && minutes) || 0;
hours = ((hours < 100) && hours) || 0;
return { hours, minutes, seconds };
}
function handleStartStopForBoundStopwatch(/* evt */) {
const stopwatch = this;
if (stopwatch.measureState === MEASURE_STATE_STOPPED) {
stopwatch.startMeasure();
} else {
stopwatch.stopMeasure();
}
}
function updateStopwatchMeasure(stopwatch) {
const dateNow = Date.now();
// has at least one second past since the last measure update?
const isUpdateMeasure = (Math.floor((dateNow - stopwatch.updateTimestamp) / 1000) >= 1);
if (isUpdateMeasure) {
stopwatch.updateTimestamp = dateNow;
// time differences in milliseconds since measuring has been started the last time.
const timePassed = (dateNow - stopwatch.measureTimestamp);
const messureValue = (timePassed + stopwatch.lastMeasuredMSecs);
Object.assign(stopwatch.measure, getMeasureFromMilliseconds(messureValue));
stopwatch.setComponentMeasure();
}
}
class Stopwatch {
constructor(node) {
this.node = node;
this.timerId = null;
this.updateCycle = this.getComponentUpdateCycle();
// for synchronizing display values of a running measure.
this.lastMeasuredMSecs = null;
this.measureTimestamp = null;
this.updateTimestamp = null;
this.measure = this.getComponentMeasure();
this.measureState = this.getComponentMeasureState();
// synchronize component data initially.
this.setComponentMeasure();
this.setComponentMeasureState();
if (this.measureState === MEASURE_STATE_RUNNING) {
this.startMeasure();
}
this.startStopHandler = handleStartStopForBoundStopwatch.bind(this);
node.addEventListener('click', this.startStopHandler);
}
destroy() {
if (this.node) {
this.node.removeEventListener('click', this.startStopHandler);
this.node.remove();
this.node = null;
delete this.node;
}
this.timerId = this.updateCycle = this.lastMeasuredMSecs = null;
this.measureTimestamp = this.updateTimestamp = null;
this.measure = this.measureState = this.startStopHandler = null;
delete this.timerId;
delete this.updateCycle;
delete this.lastMeasuredMSecs;
delete this.measureTimestamp;
delete this.updateTimestamp;
delete this.measure;
delete this.measureState;
delete this.startStopHandler;
}
getComponentMeasure() {
const result =
(/^(?<hours>\d{1,2})\:(?<minutes>\d{1,2})\:(?<seconds>\d{1,2})$/)
.exec(
this.node.dateTime
);
const {
hours,
minutes,
seconds
} = (result && result.groups) || { hours: 0, minutes: 0, seconds: 0 };
return {
hours: parseInt(hours, 10),
minutes: parseInt(minutes, 10),
seconds: parseInt(seconds, 10)
};
}
setComponentMeasure() {
const { hours, minutes, seconds } = this.measure;
const value = [
getDisplayNumber(hours),
getDisplayNumber(minutes),
getDisplayNumber(seconds)
].join(':');
this.node.dateTime = value;
this.node.innerText = value;
}
getComponentMeasureState() {
return (
((this.node.dataset.measureState || '').trim() === 'running')
&& MEASURE_STATE_RUNNING
|| MEASURE_STATE_STOPPED
);
}
setComponentMeasureState() {
this.node.dataset.measureState = this.measureState;
if (this.measureState === MEASURE_STATE_RUNNING) {
this.node.classList.add(MEASURE_STATE_RUNNING);
this.node.classList.remove(MEASURE_STATE_STOPPED);
} else {
this.node.classList.add(MEASURE_STATE_STOPPED);
this.node.classList.remove(MEASURE_STATE_RUNNING);
}
}
getComponentUpdateCycle() {
let value = parseInt(this.node.dataset.updateCycle, 10);
value = (Number.isNaN(value) && UPDATE_CYCLE_DEFAULT) || value;
return Math.max(UPDATE_CYCLE_MINIMUM, Math.min(UPDATE_CYCLE_MAXIMUM, value));
}
startMeasure() {
this.measureTimestamp = this.updateTimestamp = Date.now();
this.lastMeasuredMSecs = getMeasureInMilliseconds(this.measure);
this.timerId = setInterval(
updateStopwatchMeasure,
this.updateCycle,
this
);
this.measureState = MEASURE_STATE_RUNNING;
this.setComponentMeasureState();
}
stopMeasure() {
clearInterval(this.timerId);
this.lastMeasuredMSecs = null;
this.measureTimestamp = null;
this.updateTimestamp = null;
this.measureState = MEASURE_STATE_STOPPED;
this.setComponentMeasureState();
}/*
resetMeasure() {
Object.assign(this.measure, {
hours: 0,
minutes: 0,
seconds: 0
});
this.setComponentMeasure();
}*/
static initialize(node) {
return new Stopwatch(node);
}
}
/*export default*/function initialize() {
return Array
.from(document.body.querySelectorAll('.stopwatch-component'))
.map(Stopwatch.initialize);
}
/**
* usage
*/
const timerList = initialize();
// console.log('timerList :', timerList);
dd {
margin-bottom: 6px;
}
.stopwatch-component {
font-family: monospace;
font-size: x-large;
cursor: pointer;
}
.stopwatch-component.stopped {
text-decoration: line-through solid #999;
}
<dl>
<dt>
1st time measurement
</dt>
<dd>
<time
class="stopwatch-component"
datetime="0:0:0"
data-update-cycle="100"
data-measure-state="running">0:0:0</time>
</dd>
<dt>
2nd time measurement
</dt>
<dd>
<time
class="stopwatch-component"
datetime="99:59:33"
data-update-cycle="1000">99:59:33</time>
</dd>
<dt>
3rd time measurement
</dt>
<dd>
<time
class="stopwatch-component"
datetime="07:11:55"
data-update-cycle="500"
data-measure-state="stopped">7:11:55</time>
</dd>
</dl>
<p>Click each time measure separately for toggling its pause/proceed state.</p>
Note:
In order to keep the (re)rendering of seconds (minutes, hours) that have been passed in sync, one needs another timer approach than the one provided by the OP.
The examples run with different configurable update cycles defined by the value of the data-update-cycle attribute of a <time class="stopwatch-component"/> element. An update interval of 500msec or just 1sec is not suitable for this kind of measure task, due to setInterval being not precise enough. The running example does demonstrate exactly that.
One has to keep the displayed data in sync by constantly comparing the timestamp from starting a measure process with the timestamp from the current update process. The (re)rendering of a displayed value of cause takes place only if at least a second has passed since the last (re)rendering. But the update cycles which constantly (but not permanently) triggers the (re)rendering has to be run at a higher frequency.

Count down timer with increment

I have a switch and a timer. The switch just changes values between 0 and 1 and the timer is an interval every 5 seconds. When the interval is hit, the switch value changes (if it was 0 now it's 1, if it was 1 now it's 0) and I also have a button which forces the switch value to change and resets the timer.
I also have another timer which is running at 5ms interval and that's just to display how much time is left on the 5 second interval.
Now this is where I'm stuck. I have a button which is supposed to increment that time left by two seconds. So if three seconds have passed since the last switch, and I hit increment, now we're at six seconds until the next switch..
And that part has just been confusing me on how I should go about doing it.
Here's my html and javascript code
window.addEventListener('DOMContentLoaded', (event) => {
let timer = document.getElementById("timer");
let switchvalue = document.getElementById("switchvalue");
let force = document.getElementById("force");
let increment = document.getElementById("increment");
let boolvalue = false;
let maxtime = 5000;
var tick = Date.now();
var switchinterval = setInterval(timecounter,maxtime);
function update(){
tick = Date.now();
boolvalue = !boolvalue;
switchvalue.textContent = boolvalue;
clearInterval(switchinterval);
switchinterval = setInterval(timecounter,maxtime);
}
function timecounter(){
update();
}
let displayinterval = setInterval(() => {
let now = Date.now();
let elapsed = now-tick;
timer.textContent = maxtime-elapsed;
}, 5);
force.addEventListener("click",e=>{
update();
});
increment.addEventListener("click",e=>{
//What do I do here?
});
});
<html>
<head>
<script src="timer.js"></script>
</head>
<body>
<div id="timer">10</div>
<div id="switchvalue">false</div>
<button id="force">Switch</button>
<button id="increment">Increment</button>
</body>
</html>
I'm not sure how to make that increment button function. It seems like a simple enough problem to solve..but my brains not working
If I understood your question correctly, your increment button should simply add two seconds, right?
increment.onclick =e=>
{
tick += 2000 // add 2s
}
const timer = document.getElementById("timer")
, switchvalue = document.getElementById("switchvalue")
, force = document.getElementById("force")
, increment = document.getElementById("increment")
;
let boolvalue = false
, maxtime = 5000
, tick = Date.now()
, switchinterval
, displayinterval
;
switchinterval = setInterval(timecounter, maxtime)
;
function update()
{
tick = Date.now()
boolvalue = !boolvalue
switchvalue.textContent = boolvalue
clearInterval(switchinterval)
switchinterval = setInterval(timecounter, maxtime)
}
function timecounter()
{
update()
}
displayinterval = setInterval(_=>
{
let now = Date.now()
, elapsed = now - tick
timer.textContent = maxtime - elapsed
}, 5)
force.onclick =e=>
{
update()
}
increment.onclick =e=>
{
tick += 2000 // add 2s
}
<div id="timer">?</div>
<div id="switchvalue">false</div>
<button id="force">Switch</button>
<button id="increment">Increment</button>
But you forgot to take into account that the delay indicated in setInterval is not reliable, it represents just a hypothetical delay according to the availability of the system, most often (always) it is late.
If you want to have a reliable delay, you must use the value of the system clock to check the elapsed delay.
Which is precisely the case study of your exercise, and which has the merit of using only one setInterval to do everything:
const timer = document.getElementById("timer")
, switchvalue = document.getElementById("switchvalue")
, force = document.getElementById("force")
, increment = document.getElementById("increment")
;
let boolvalue = false
, maxtime = 5000
, timeTarget = Date.now() + maxtime
, interval_5ms
;
const timeSwich =_=>
{
switchvalue.textContent = boolvalue = !boolvalue
timeTarget = Date.now() + maxtime
}
interval_5ms = setInterval(_=>
{
let tim = timeTarget - Date.now()
if ( tim<=0 )
{
timeSwich()
tim = maxtime
}
timer.textContent = tim
}, 5)
force.onclick = timeSwich
increment.onclick =_=>
{
timeTarget = Math.min((timeTarget +2000), Date.now() + maxtime)
// timeTarget += 2000 // add 2s
}
<div id="timer">?</div>
<div id="switchvalue">false</div>
<button id="force">Switch</button>
<button id="increment">Increment</button>

HTML 5 Audio Player remaining time show delay

I have a problem with an audio player, when users press play the start-time timer is showing instantly, but remaining-time timer shows with a delay. I'm relatively new to JS, so I can not identify the problem on my own.
Can someone can help me with synching timers (start and remaining) show on play event?
CodePen
var isSeeking = false;
var seek = document.getElementById("seekObj");
var player = document.getElementById("player");
SetSeekColor();
function calculateTotalValue(length) {
var minutes = Math.floor(length / 60),
seconds_int = length - minutes * 60,
seconds_str = seconds_int.toString(),
seconds = seconds_str.split(".")[0],
temp_min = minutes.toString().length === 1 ? "0" + minutes : minutes,
temp_sec = seconds.toString().length === 1 ? "0" + seconds : seconds;
return temp_min + ":" + temp_sec;
}
function calculateCurrentValue(_seconds) {
function padTime(t) {
return t < 10 ? "0" + t : t;
}
if (typeof _seconds !== "number") return "";
if (_seconds < 0) {
_seconds = Math.abs(_seconds);
//console.log(_seconds);
}
var hours = Math.floor(_seconds / 3600),
minutes = Math.floor((_seconds % 3600) / 60),
seconds = Math.floor(_seconds % 60);
var hour = hours > 0 ? padTime(hours) + ":" : "";
return hour + padTime(minutes) + ":" + padTime(seconds);
}
function setupSeek() {
seek.max = player.duration;
}
function seekAudio() {
isSeeking = true;
player.currentTime = seek.value;
isSeeking = false;
}
var prevcurrentime = 0;
function initProgressBar() {
if (!isSeeking) {
seek.value = player.currentTime;
}
var length = player.duration;
var current_time = player.currentTime;
// calculate total length of value
var totalLength = calculateTotalValue(length);
// calculate current value time
var currentTime = calculateCurrentValue(current_time);
if (player.readyState === 4) {
jQuery(".end-time").html(totalLength);
jQuery(".start-time").html(currentTime);
}
//checking if the current time is bigger than the previous or else there will be sync different between remaining and current
if (currentTime > prevcurrentime) {
//calculate the remaining time
var rem_time = length - current_time;
jQuery(".rem-time").html(calculateCurrentValue(rem_time));
}
//setting the previouscurrent time to this current time
prevcurrentime = currentTime;
if (player.currentTime == player.duration) {
$("#play-btn").removeClass("pause");
}
}
function initPlayers(num) {
// pass num in if there are multiple audio players e.g 'player' + i
for (var i = 0; i < num; i++) {
(function() {
// Variables
// ----------------------------------------------------------
// audio embed object
var playerContainer = document.getElementById("player-container"),
player = document.getElementById("player"),
isPlaying = false,
playBtn = document.getElementById("play-btn");
// Controls Listeners
// ----------------------------------------------------------
if (playBtn != null) {
playBtn.addEventListener("click", function() {
togglePlay();
});
}
// Controls & Sounds Methods
// ----------------------------------------------------------
function togglePlay() {
if (player.paused === false) {
player.pause();
isPlaying = false;
$("#play-btn").removeClass("pause");
} else {
$(".start-time").html("");
player.play();
$("#play-btn").addClass("pause");
isPlaying = true;
}
}
})();
}
}
looking good, this is an error in the html. In this piece of code just replace the class rem-time by end-time.
<small style="float: right; position: relative; right: 21px;" class="end-time" onclick="showhideRemaining(this)"></small>
I think the root of your problem lies within the performance of your code. I can't see a big time difference between the two counters, but here are some suggested improvements:
You have the padTime function, so use it (see point 2)!
function padTime(t) {
return t < 10 ? "0" + t : t;
}
no unnecessary or early conversion to strings:
function calculateTotalValue(length) {
var minutes = Math.floor(length / 60);
var seconds = Math.floor(length - minutes * 60);
// use the padTime function here with numbers
return padTime(minutes) + ":" + padTime(seconds);
}
do not query the elements over and over again:
if (player.readyState === 4) {
jQuery(".end-time").html(totalLength);
jQuery(".start-time").html(currentTime);
}
Here, instead of querying the elements (jQuery(".end-time")) every time in your ontimeupdate callback, save the references in variables outside of the callback function.
limit color updates.
setInterval(function() {
SetSeekColor();
}, 34);
Updating the color every millisecond is just overkill. 34 milliseconds should equal something around 30fps.
I noticed you have are planning to have multiple players on one page (initPlayers(num)). Here a few thoughts:
When you initialise the players, save each single player with its UI elements in an Object
initPlayers(jQuery("#player-container").length);: IDs are (must be) unique in an entire HTML Document. This wont work, change it to a class.

JS. setInterval does not increment value of variables in external scope

I trying to bring my timer update the value of all let variables. But unfortunally my setInterval fucntion does not want to do this.
Where is my problem located? Thanks
function defineInterval(intervalInHours = 1, precision = 3600, disableInterval = 900, time = 200000) {
let interval = 0
let timeLeftInInterval = 0
let timePercent = 0
let timeDisabled = 0
setInterval(() => {
interval = intervalInHours * precision;
timeLeftInInterval = (time % interval);
console.log(interval, 'interval', timeLeftInInterval, 'timeLeftInInterval ', timeDisabled, 'timeDisabled', timePercent, 'timePercent') // 3600, 2000, 1600, 59 on output
if (disableInterval >= timeLeftInInterval) {
timeDisabled = disableInterval - timeLeftInInterval;
timePercent = (timeDisabled / disableInterval) * 100;
} else {
timeDisabled = interval - timeLeftInInterval;
timePercent = (timeDisabled / (interval++ - disableInterval) * 100);
interval++
}
}, 1000)
}
defineInterval();
Possible issues:
interval = intervalInHours * precision; is getting reset to 3600 every time. Move it above setInterval.
You are not doing anything to change values in if statement, it's not impacting anything. Changing timeDisabled and timePercent is not impacting anything further. It will give same values after every timeout. Are you missing an interval++?
You are doing interval++ two times in your else statement.

Countdown Timer Objects - Javascript

I would like to create a simple timer in Javascript that counts down from a given time until it hits 0. I found this tutorial which worked perfectly. My problem is that I need to place multiple timers on the same page. This tutorial obviously won't do that because it uses global variables (I'm new to JS/Programming so I might not be using the right terms). I tried to re-create the same thing only creating each timer as it's own Object so that they don't interfere with eachother. This is what I have.
function taskTimer(name, startTime) {
this.timer = name;
this.totalSeconds = startTime;
this.tick = function() {
if (this.totalSeconds <= 0) {
return;
}
this.totalSeconds -= 1;
this.updateTimer();
// window.setTimeout("this.tick()", 1000);
};
this.updateTimer = function(){
this.seconds = this.totalSeconds;
this.hours = Math.floor(this.seconds / 3600);
this.seconds -= this.hours * (3600);
this.minutes = Math.floor(this.seconds / 60);
this.seconds -= this.minutes * (60);
this.timeString = this.leadingZero(this.hours) + ":" + this.leadingZero(this.minutes) + ":" + this.leadingZero(this.seconds);
return this.timeString;
};
this.leadingZero = function(time){
return (time < 10) ? "0" + time : + time;
};
}
var testTimer = new taskTimer("timer", 30);
testTimer.tick();
I created one at the end there. Running
testTimer.updateTimer(); returns 00:00:30 which is correct, but running testTimer.tick(); returns no value. There is obviously something wrong with that part of the code I just can't figure it out.
You've got a few problems.
You're calling updateTimer() inside of your tick method, so it
won't ever reach outside of there unless you return it.
With your current setup, you'd have to call tick manually every time you wanted to update the clock, and if you don't do that precisely every one second the timer will be inaccurate.
To go with #2, you shouldn't decrement totalSeconds like you are because it isn't guaranteed that it will be exactly one second between triggers of your timeout. Use dates instead.
Here's what I would do: http://jsfiddle.net/R4hnE/3/
// I added optional callbacks. This could be setup better, but the details of that are negligible.
function TaskTimer(name, durationInSeconds, onEnd, onTick) {
var endTime,
self = this, // store a reference to this since the context of window.setTimeout is always window
running = false;
this.name = name;
this.totalSeconds = durationInSeconds;
var go = (function tick() {
var now = new Date().getTime();
if (now >= endTime) {
if (typeof onEnd === "function") onEnd.call(self);
return;
}
self.totalSeconds = Math.round((endTime - now) / 1000); // update totalSeconds placeholder
if (typeof onTick === "function") onTick.call(self);
window.setTimeout(tick, 1000 / 12); // you can increase the denominator for greater accuracy.
});
// this is an instance method to start the timer
this.start = function() {
if (running) return; // prevent multiple calls to start
running = true;
endTime = new Date().getTime() + durationInSeconds * 1000; // this is when the timer should be done (with current functionality. If you want the ability to pause the timer, the logic would need to be updated)
go();
};
}
// no reason to make this an instance method :)
TaskTimer.prototype.toTimeString = function() {
var hrs = Math.floor(this.totalSeconds / 60 / 60),
min = Math.floor(this.totalSeconds / 60 - hrs * 60),
sec = this.totalSeconds % 60;
return [hrs.padLeft("0", 2), min.padLeft("0", 2), sec.padLeft("0", 2)].join(" : ");
};
var task = new TaskTimer("task1", 30, function() {
document.body.innerHTML = this.toTimeString();
alert('done');
}, function() {
document.body.innerHTML = this.toTimeString();
});
I always have problems with this and in one instance, within the function, I had to redefine it:
this.tick = function() {
self=this;
if (self.totalSeconds <= 0) {
return;
}
self.totalSeconds -= 1;
self.updateTimer();
// window.setTimeout("self.tick()", 1000);
};
Here is another post about that: var self = this?
My version, you can see at:
http://fiddle.jshell.net/hmariod/N7haK/4/
var tmArray = new Array();
var timerRef, timerId=0;
function newTimer(){
try{
if(tmArray.length > 4) throw "Too much timers";
var countDown = parseInt(document.getElementById("tCountown").value,10);
if(isNaN(countDown)) throw "tCountown is NaN";
var tmName = document.getElementById("tName").value;
var nt = new taskTimer(++timerId, tmName, countDown);
createTmElement(timerId, tmName);
tmArray.push(nt);
if(!timerRef) timerRef = setInterval(timerFn, 1000);
showTimers();
}catch(er){
alert("newTimer:" + er);
}
}
function taskTimer(id, name, tCountown) {
this.id = id;
this.tName = name;
this.tCountown = tCountown;
}
function timerFn(){
try{
var i;
killTimer = true;
for(i = 0; i < tmArray.length; i++){
tmArray[i].tCountown--;
if(tmArray[i].tCountown < 0){
tmArray[i].tCountown = 0;
}else{
killTimer = false;
}
}
if(killTimer) clearInterval(timerRef);
showTimers();
}catch(er){
clearInterval(timerRef);
aler("timerFn: " + er);
}
}

Categories

Resources