2

I usually don't like to post about subjects I'm not to familiar with (working with time and dates in javascript has always been a weakness of mine), but I am in desperate need of some help.

I'm using this link to display a countdown timer on clients website. It should be pretty straight forward, right? I implemented it like this:

<script type="text/javascript">
// set the date we're counting down to
var target_date = new Date('Sep, 18, 2015').getTime();

// variables for time units
var days, hours, minutes, seconds;

// get tag element
var countdown = document.getElementById('countdown');

// update the tag with id "countdown" every 1 second
setInterval(function () {

    // find the amount of "seconds" between now and target
    var current_date = new Date().getTime();
    var seconds_left = (target_date - current_date) / 1000;

    // do some time calculations
    days = parseInt(seconds_left / 86400);
    seconds_left = seconds_left % 86400;

    hours = parseInt(seconds_left / 3600);
    seconds_left = seconds_left % 3600;

    minutes = parseInt(seconds_left / 60);
    seconds = parseInt(seconds_left % 60);

    // format countdown string + set tag value
    countdown.innerHTML = '<span class="days">' + days +  ' <b>Days</b></span> <span class="hours">' + hours + ' <b>Hours</b></span> <span class="minutes">'
    + minutes + ' <b>Minutes</b></span> <span class="seconds">' + seconds + ' <b>Seconds</b></span>';  

}, 1000);
</script>

Style

<style>
.container {
  margin: 0px auto;
  padding: 0px;
}

#main { 
  background: #3B3B3B;
  height: 430px;
}

.content {
  padding: 10px 44px;
}

.text {
  border-bottom: 1px solid #262626;
  margin-top: 40px;
  padding-bottom: 40px;
  text-align: center;
}

.text h2 {
  color: #E5E5E5;
  font-size: 30px;
  font-style: normal;
  font-variant: normal;
  font-weight: lighter;
  letter-spacing: 2px;
}

.counter {
  background: #2C2C2C;
  -moz-box-shadow:    inset 0 0 5px #000000;
  -webkit-box-shadow: inset 0 0 5px #000000;
  box-shadow:         inset 0 0 5px #000000;
  min-height: 150px;
  text-align: center;
}

.counter h3 {
  color: #E5E5E5;
  font-size: 14px;
  font-style: normal;
  font-variant: normal;
  font-weight: lighter;
  letter-spacing: 1px;
  padding-top: 20px;
  margin-bottom: 30px;
}

#countdown {
  color: #FFFFFF;
}

#countdown span {
  color: #E5E5E5;
  font-size: 26px;
  font-weight: normal;
  margin-left: 20px;
  margin-right: 20px;
  text-align: center;
}
</style>

HTML

<div class="container">
<div class="row">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
<div id="main">
<div class="content">
<div class="text">
<h2>This Website Is Under Construction</h2>
</div> <!-- /.Text Div -->
<div class="counter">
<h3>Estimated Time Remaining Before Launch:</h3>
<div id="countdown">
</div><!-- /#Countdown Div -->
</div> <!-- /.Counter Div -->
</div> <!-- /.Content Div -->
</div> <!-- /#Main Div -->
</div> <!-- /.Columns Div -->
</div> <!-- /.Row Div -->
</div> <!-- /.Container Div -->

Output

screenshot of the output

Firefox gives me the following error:

TypeError: Countdown is null

Chrome tells me the following:

Uncaught TypeError: cannot set property 'innerHTML' of null

The code is implemented exactly as above but I am getting the errors as shown in above images. However, in this fiddle I have created it is working. Weird, why is this?

Jeroen
  • 53,290
  • 30
  • 172
  • 279
Marilee
  • 1,570
  • 3
  • 19
  • 47
  • 1
    When posting a question, it helps (easier to answer so you'll get faster results and happier volunteers + better to understand/find for people with similar issues) if you trim the example to the *minimal* set of code. For one, I'm sure just about all of the CSS can be left out and leave the example unchanged in behavior? – Jeroen Sep 13 '15 at 12:48
  • 1
    Off-topic, but note that you're counting down to the user's local time, so the "time before launch" will show different values to people in different time zones. – JJJ Sep 13 '15 at 12:58

3 Answers3

2

are you triggering this js code after document is ready? You are calling DOM object with id countdown but maybe it is not rendered yet?

Take a look at jQuery document ready function

All in all it should looks like:

    $( document ).ready(function() 
    {
        var target_date = new Date('Sep, 18, 2015').getTime();

        // variables for time units
        var days, hours, minutes, seconds;

        // get tag element
        var countdown = document.getElementById('countdown');

        ... //etc...
    });
m.antkowicz
  • 11,566
  • 12
  • 33
2

You need to make sure your code runs after the document has been fully loaded, or the elementById may not exist yet when it runs. This is what's happening in your case: the countdown variable will be null because the element doesn't exist in the document yet when your code executes.

A quick fix which is also present in your jsfiddle (check out the bottom right frame's source) could be to place the <script> tag below the element so the countdown element will probably exist when your code executes.

A better fix, since you tag your question jQuery, so you can do this by wrapping your code in $(document).ready() or its shorthand:

$(function() {
  // Your code...
});

If you don't need to support IE8 and below, you can consider using a Vanilla JS alternative.


Here's a runnable snippet with the jQuery solution:

$(function() {
  var target_date = new Date('Sep, 18, 2015').getTime();
  var days, hours, minutes, seconds;
  var countdown = document.getElementById('countdown');

  setInterval(function () {

    // find the amount of "seconds" between now and target
    var current_date = new Date().getTime();
    var seconds_left = (target_date - current_date) / 1000;

    // do some time calculations
    days = parseInt(seconds_left / 86400);
    seconds_left = seconds_left % 86400;

    hours = parseInt(seconds_left / 3600);
    seconds_left = seconds_left % 3600;

    minutes = parseInt(seconds_left / 60);
    seconds = parseInt(seconds_left % 60);

    // format countdown string + set tag value
    countdown.innerHTML = '<span class="days">' + days +  ' <b>Days</b></span> <span class="hours">' + hours + ' <b>Hours</b></span> <span class="minutes">'
    + minutes + ' <b>Minutes</b></span> <span class="seconds">' + seconds + ' <b>Seconds</b></span>';  

  }, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>Estimated Time Remaining Before Launch:</h3>
<div id="countdown"></div>

And here's another one that also makes sure the counter starts immediately instead of after the first 1sec interval:

$(function() {
  var target_date = new Date('Sep, 18, 2015').getTime();
  var days, hours, minutes, seconds;
  var countdown = document.getElementById('countdown');

  function updateCounter() {

    // find the amount of "seconds" between now and target
    var current_date = new Date().getTime();
    var seconds_left = (target_date - current_date) / 1000;

    // do some time calculations
    days = parseInt(seconds_left / 86400);
    seconds_left = seconds_left % 86400;

    hours = parseInt(seconds_left / 3600);
    seconds_left = seconds_left % 3600;

    minutes = parseInt(seconds_left / 60);
    seconds = parseInt(seconds_left % 60);

    // format countdown string + set tag value
    countdown.innerHTML = '<span class="days">' + days +  ' <b>Days</b></span> <span class="hours">' + hours + ' <b>Hours</b></span> <span class="minutes">'
    + minutes + ' <b>Minutes</b></span> <span class="seconds">' + seconds + ' <b>Seconds</b></span>';  

  }
  
  updateCounter();
  
  setInterval(updateCounter, 1000);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3>Estimated Time Remaining Before Launch:</h3>
<div id="countdown"></div>
Community
  • 1
  • 1
Jeroen
  • 53,290
  • 30
  • 172
  • 279
  • as always you have been very helpfull to me....you must be one of my favorite users on this site...thank you very much for the effort, im quickly gonna implement it into the website and give you feedback. As for your comment above noted and will keep it in mind for future reference – Marilee Sep 13 '15 at 13:03
1

And if you don't want jQuery for this (which might be overkill) do wrap your setInterval method with a startCount method and call that in the body onload event.

function startCount() {

    // update the tag with id "countdown" every 1 second
    setInterval(function () {

        // find the amount of "seconds" between now and target
        var current_date = new Date().getTime();
        var seconds_left = (target_date - current_date) / 1000;

        // do some time calculations
        days = parseInt(seconds_left / 86400);
        seconds_left = seconds_left % 86400;

        hours = parseInt(seconds_left / 3600);
        seconds_left = seconds_left % 3600;

        minutes = parseInt(seconds_left / 60);
        seconds = parseInt(seconds_left % 60);

        // format countdown string + set tag value
        countdown.innerHTML = '<span class="days">' + days +  ' <b>Days</b></span> <span class="hours">' + hours + ' <b>Hours</b></span> <span class="minutes">'
        + minutes + ' <b>Minutes</b></span> <span class="seconds">' + seconds + ' <b>Seconds</b></span>';  

    }, 1000);

}

and in the body tag

<body onload='startCount();'>
Ason
  • 79,264
  • 11
  • 79
  • 127