Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setInterval inside .each() only working for last interval?

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)
});
like image 398
Sandro Avatar asked Jul 27 '20 09:07

Sandro


People also ask

Does setInterval wait for function to finish?

The setInterval() function is commonly used to set a delay for functions that are executed again and again, such as animations. You can cancel the interval using clearInterval() . If you wish to have your function called once after the specified delay, use setTimeout() .

What does setInterval () method do in JS?

JavaScript setInterval() method. The setInterval() method in JavaScript is used to repeat a specified function at every given time-interval. It evaluates an expression or calls a function at given intervals. This method continues the calling of function until the window is closed or the clearInterval() method is called ...


1 Answers

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));
});
like image 82
Rory McCrossan Avatar answered Sep 27 '22 16:09

Rory McCrossan