Goal:
Im looping through several .event elements using jQuery's each function. I am calculating a timer countdown using information coming from hidden span elements inside each .event class. I am using setInterval() to recalculate the remaining time every second.
Problem:
All my calculations work perfectly – but only for the last interval. Each interval seems to overwrite the calculation from the one before. Meaning: only the last .event is even getting an output. All previous .event are not even getting any output. Using logs before and after the interval, I was able to narrow my error down to the setInterval function. How can I prevent each interval from overwriting the one before? Or is my error somewhere I did not even think of yet?
Code:
$('.event').each(function() {
$event = $(this);
// SET FUTURE DATE
$futureDate = $event.find($('.event-time'));
$countdownDate = new Date($futureDate.text()).getTime();
setInterval(function() {
// SET TODAYS DATE
$now = new Date().getTime();
// DIFFERENCE NOW AND FUTURE DATE
$diff = $countdownDate - $now;
// TIME CALCULATIONS FOR d, h, m, s
$days = Math.floor($diff / (1000 * 60 * 60 * 24));
$hours = Math.floor(($diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
$minutes = Math.floor(($diff % (1000 * 60 * 60)) / (1000 * 60));
$seconds = Math.floor(($diff % (1000 * 60)) / 1000);
// OUTPUT
$event.find('.clock .val-d').html($days);
$event.find('.clock .val-h').html($hours);
$event.find('.clock .val-m').html($minutes);
$event.find('.clock .val-s').html($seconds);
}, 1000)
});
The problem is because when the function within your interval runs the loop has finished, so $event
will only ever refer to the last .event
element in the jQuery object.
The simple fix for this, assuming you can use ES6, is to use the let
keyword to define the $event
:
$('.event').each(function() {
let $event = $(this);
// the rest of your code...
});
If you can't use ES6 then you'll need to use a closure to retain the scope of $(this)
:
$('.event').each(function() {
(function($event) {
$futureDate = $event.find($('.event-time'));
$countdownDate = new Date($futureDate.text()).getTime();
setInterval(function() {
$now = new Date().getTime();
$diff = $countdownDate - $now;
// TIME CALCULATIONS FOR d, h, m, s
$days = Math.floor($diff / (1000 * 60 * 60 * 24));
$hours = Math.floor(($diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
$minutes = Math.floor(($diff % (1000 * 60 * 60)) / (1000 * 60));
$seconds = Math.floor(($diff % (1000 * 60)) / 1000);
$event.find('.clock .val-d').html($days);
$event.find('.clock .val-h').html($hours);
$event.find('.clock .val-m').html($minutes);
$event.find('.clock .val-s').html($seconds);
}, 1000)
})($(this));
});