[RESOLVED] Timer countdown function alteration

Status
Not open for further replies.

olliepop

Member
Messages
138
Reaction score
0
Points
16
Hey everyone - the function discussed in this thread is at the bottom of this post.

What this function does is countdown the value of an HTML table-cell to zero (minus 1 every second) then stop counting that specific cell when it's finished. This works perfectly, the problem is that when it is called AGAIN for a different table-cell, the previous cell starts reducing its value by 2 every second instead of 1. This function supports the Hour:Minute:Second format.

So, how would i make this function so that i can call an infinite number of different table cells, and the previous table cells timers would not be affected (they would still countdown 1 per second as they should)?


Thank you so much. I have been stuck on this problem for 2 weeks and just left my project dormant because of it. This simple problem has struck me from behind and destroyed my passion for the project - please help me get back on track!

-Ollie



This is the code which CALLS the function, where $i is 1-5 inclusive, defined by PHP:
Code:
timer('ff".$i."', ". rand(1,100) .");
This is the BODY of the function itself, called by the above command
Code:
var running = new Array(50);
function timer(data, id)
{
    //clearTimeout(id[data]);
    var id=new Array(50);
    // usage: var id=new Array(50); timer('cq0');
    dat=document.getElementById(data);
    var time=(dat.innerHTML).split(":"); 
    var done=0;
    if(dat.innerHTML == null) {
        done = 1;
        alert('null');
    }
    if (time[2]>0) time[2]--;
    else
    {
        time[2]=59;
        if (time[1]>0) time[1]--;
        else
        {
            time[1]=59;
            if (time[0]>0) time[0]--;
            else { 
            clearTimeout(id[data]); 
            done=1;
            running[data] = 0;
            renderStack();
            }
            
        }
        
    }
    if (!done)
    {
        dat.innerHTML=time[0]+":"+time[1]+":"+time[2];
        id[data]=setTimeout("timer('"+data+"')", 1000);
        running[data] = 1;
    }
}


---------- Post added at 08:13 AM ---------- Previous post was at 04:10 AM ----------

Resolved!
 
Last edited:

misson

Community Paragon
Community Support
Messages
2,572
Reaction score
72
Points
48
On an unrelated note, I notice you're ending the double quoted string to concatenate $i. You can interpolate variables directly into double quoted and heredoc strings. The PHP code can thus be made more readable:

PHP:
"...
timer('ff$i', " . rand(1,100) . ");
..."

Or even:
PHP:
$r = rand(1,100);
# or however the JS code is output
echo <<<EOS
...
timer('ff$i', $r);
...
EOS;

You can make the JS slightly more efficient by using setInterval rather than setTimeout and by using anonymous functions and closures rather than strings containing JS code.
Code:
// 'map' is used for added functionality: display countdown timer fields
Array.prototype.map = function(f) {
    var arr = [];
    for (var i=0; i<this.length; ++i) {
        arr[i] = f(this[i]);
    }
}

var running = [];
/* timer: Start counting down time. When done, render the stack (?) and (optionally) invoke an arbitrary function.
 * Arguments:
 * - data: HTML element or element ID. Contains countdown clock.
 * - onDone (optional): function to invoke when countdown finishes.
 */
function timer(data, onDone) {
    var countdownIval, time, done;
    if (typeof data == 'string') {
        data=document.getElementById(data);
    }
    /* decrTime: Decrement time.
     * Returns 'true' if time is out, 'false' otherwise
     */
    function decrTime() {
        if (time[2]>0) time[2]--;
        else {
            time[2]=59;
            if (time[1]>0) time[1]--;
            else {
                time[1]=59;
                if (time[0]>0) time[0]--;
                else { 
                    return true;
                }
            }
        }
        return false;
    }
    /* countdown: Count down display 1 second. Self canceling when timer reaches 0,
     *   at which point optional done handler is invoked and stack is rendered.
     * Returns 'true' if not yet done.
     */
    function countdown() {
        done=decrTime();
        data.innerHTML=time.map(function(n) {if (n<10) return '0'+n; return n;}).join(':');
        if (done) {
            clearInterval(countdownIval);
            running[data.id] = 0;
            onDone();
            renderStack();
            return false;
        }
        return true;
    }
    if (data.innerHTML == null) {
        if (console) {
            console.log("countdown "+data.id+"'s content is unexpectedly null.");
        }
    } else {
        time=data.innerHTML.split(":");
        running[data.id] = 1;
        if (countdown()) {
            countdownIval = setInterval(countdown, 1000);
        }
    }
}

Or with simpler decrementing:
Code:
var running = [];
/* timer: Start counting down time. When done, render the stack (?) and (optionally) invoke an arbitrary function.
 * Arguments:
 * - data: HTML element or element ID. Contains countdown clock.
 * - onDone (optional): function to invoke when countdown finishes.
 */
function timer(data, onDone) {
    var countdownIval, time, done;
    if (typeof data == 'string') {
        data=document.getElementById(data);
    }
    /* s2hms: Convert seconds to hours, minutes, seconds.
     * Arguments:
     * - secs: integer representing seconds.
     * Returns string formatted as HH:MM:SS.
     */
    function s2hms(secs) {
        return [secs/3600 , (secs / 60) % 60, secs % 60].map(function(n) {if (n<10) return '0'+n; return n;}).join(':');
    }
    /* countdown: Count down display 1 second. Self canceling when timer reaches 0,
     *   at which point optional done handler is invoked and stack is rendered.
     * Returns 'true' if not yet done.
     */
    function countdown() {
        if (time > 0) {
            --time;
        }
        data.innerHTML=s2hms(time);
        if (time == 0) {
            clearInterval(countdownIval);
            running[data.id] = 0;
            onDone();
            renderStack();
            return false;
        }
        return true;
    }
    if (data.innerHTML == null) {
        if (console) {
            console.log("countdown "+data.id+"'s content is unexpectedly null.");
        }
    } else {
        time = data.innerHTML.split(":");
        time = ((time[0] * 60) + time[1]) * 60 + time[2];
        running[data.id] = 1;
        if (countdown()) {
            countdownIval = setInterval(countdown, 1000);
        }
    }
}

Both still need a little more error handling to cover cases where the 'data' element doesn't contain a properly formatted time string, and could potentially use an optional 'time' argument so the 'data' element doesn't need to hold a time string.
 
Status
Not open for further replies.
Top