1

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 );
2
  • Ahh, thanks for breaking that down! Niels figured out the issue, but I'm glad you explained the reasoning behind it. Commented Apr 21, 2013 at 13:05
  • I changed my comment to an answer since the explanation in it was really more of an answer than a comment. Commented Apr 21, 2013 at 13:09

3 Answers 3

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! Works in Fiddle now, but still doesn't work live on my site. Going to go through and diagnose it now that I know it's a working function, though.
Figured it out. O.o I was updating my script file locally and thought it was the one on the server. Thanks again, man!
1

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().

Comments

0

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);

2 Comments

You might also want to consider if (false !== callback(o)) o.timer = window.setTimeout(f, ms);, i.e. returning false in the callback stops the countdown. I've already overkilled this enough so it's a comment.
Further, if you want an action to happen upon reaching 0 then e.g. either add a new parameter for a second function (or set the values in o to 0 for same callback) and add an else to match if (remain > 0) {, which then invokes this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.