Marlon
Marlon

Reputation: 597

Creating a Countdown Using Javascript

I found this in my search to create a JavaScript Countdown, but it doesn't seem to work for me. I'm surprised, as no one else seems to have reported having a problem. I must be missing something fundamental and I didn't know where else to turn, but here.

https://gist.github.com/nithinbekal/299417

Here is the code live on JSFiddle where it doesn't seem to function for me, either.

http://jsfiddle.net/96TWk/

function updateWCTime() {
    now      = new Date();
    kickoff  = Date.parse("April 27, 2013 09:00:00");
    diff = kickoff - now;

    days  = Math.floor( diff / (1000*60*60*24) );
    hours = Math.floor( diff / (1000*60*60) );
    mins  = Math.floor( diff / (1000*60) );
    secs  = Math.floor( diff / 1000 );

    dd = days;
    hh = hours - days  * 24;
    mm = mins  - hours * 60;
    ss = secs  - mins  * 60;

        document.getElementById("countdown")
            .innerHTML =
                dd + ' days ' +
                hh + ' hours ' +
                mm + ' minutes ' +
                ss + ' seconds';
}
setInterval('updateWCTime()', 1000 );

Upvotes: 1

Views: 3273

Answers (3)

Paul S.
Paul S.

Reputation: 66404

I'll propose an entirely different way of doing a countdown timer; a generator with a callback. At first you might wonder, why would I do it this way? But using a generator saves you a lot of code in re-used things. I've also used window.setTimeout This is to ensure that you don't have nasty things happen if your callback takes longer to execute than your interval.

The comments through the code should help you understand what is happening.

// createCountDown(Date end_time [, Function callback, Integer ms_interval])
// returns an Object properties: ms, ss, mm, hh, dd, MM, yy, timer (current)
// same Object is passed as parameter 1 to callback
function createCountDown(time, callback, ms) {
    var future = time.valueOf(), // cache these to save re-calling them later
        f_ms = time.getUTCMilliseconds(),
        f_ss = time.getUTCSeconds(),
        f_mm = time.getUTCMinutes(),
        f_hh = time.getUTCHours(),
        f_dd = time.getUTCDate(),
        f_MM = time.getUTCMonth(),
        f_yy = time.getUTCFullYear(),
        o = {timer: null}; // an object to make life easier
    var f = function () { // the function that will handle the setTimeout loops
        var d = new Date(), // the current time of each loop
            remain = future - d.valueOf(); // difference (in ms)
        if (remain > 0) {
            // Totals
            o['total_ms'] = remain; // if you'll never need all these, you can
            o['total_ss'] = remain /     1000 | 0; // comment or cut them out
            o['total_mm'] = remain /    60000 | 0;
            o['total_hh'] = remain /  3600000 | 0;
            o['total_dd'] = remain / 86400000 | 0;
            // Differences (via UTC)
            o['ms'] = (1000 + f_ms - d.getUTCMilliseconds()) % 1000; // same
            o['ss'] = (  60 + f_ss - d.getUTCSeconds()     ) %   60;
            o['mm'] = (  60 + f_ss - d.getUTCMinutes()     ) %   60;
            o['hh'] = (  24 + f_hh - d.getUTCHours()       ) %   24;
            o['dd'] = (       f_dd - d.getUTCDate()        )       ; // below
            o['MM'] = (  12 + f_MM - d.getUTCMonth()       ) %   12;
            o['yy'] = (       f_yy - d.getUTCFullYear()    )       ;
            if (o['dd'] < 0) { // fix for negative days
                d.setUTCMonth(d.getUTCMonth() + 1);
                d.setUTCDate(0); // using number of days in current month
                o['dd'] + d.getUTCDate();
            }
            callback(o); // invoke your callback
            o.timer = window.setTimeout(f, ms); // set up next loop
        }
    }
    ms || ms === 0 || (ms = 200); // default ms if not set
    callback || (callback = function () {}); // default empty fn
    f(); // start off the whole looping
    return o;
}

Now write your callback, this is much shorter, as you've got the long stuff out of the way. console.log makes it easy for demonstrative purposes.

function updateWCTime(o) {
    console.log(
        o['total_dd'] + ' days ' +
        o['hh'] + ' hours ' +
        o['mm'] + ' minutes ' +
        o['ss'] + ' seconds'
    );
}

Finally, initiate it.

createCountDown(new Date("April 27, 2013 09:00:00"), updateWCTime);

Upvotes: 0

jfriend00
jfriend00

Reputation: 708136

You can fix your jsFiddle by either changing to:

setInterval(updateWCTime, 1000 );

or by changing the setting on the left panel of the jsFiddle from onload to either of the no wrap options. Here's a demonstration on only changing the jsFiddle left panel setting to "No wrap - in ": http://jsfiddle.net/jfriend00/rdj96/

Here's the explanation for why it didn't work. When you pass a string to setInterval() like this:

setInterval('updateWCTime()', 1000 );

The javascript intepreter uses eval() to evaluate the string and the function must be found in the global scope. But, because you have onload in the left panel in the jsFiddle, all your javascript is inside another function (e.g. not global) so eval() cannot find that function.

Changing your code to

setInterval(updateWCTime, 1000 ); 

allows javascript to just use a normal function reference and it can then find the function in your local scope (doesn't have to be global).

FYI, you should pretty much never pass a string to setInterval().

Upvotes: 1

Niels
Niels

Reputation: 49949

Change the interval to (live fiddle: http://jsfiddle.net/96TWk/1/)

setInterval(updateWCTime, 1000 );

The console says that the function updateWCTime is not found, I don't know excactly why. Cu's it seems ok.

Upvotes: 2

Related Questions