I have a page with multiple .countdown-element
divs which I want to contain a countdown.
I am iterating through each .countdown-element
and attempting to apply a countdown timer to each of them.
The $(this).html()
parts in the setInterval
do not trigger. I assume this is related to using .each
and it’s going through the other .countdown-element
divs before it can run.
How can I get the countdown to be applied to each of the .countdown-element
divs?
$( '.countdown-element' ).each( function() { // Set the date we're counting down to var countDownDate = new Date( $(this).attr('data-countdown-to') ).getTime(); console.log( 'test: ' + countDownDate ); // Update the count down every 1 second var x = setInterval(function() { // Get today's date and time var now = new Date().getTime(); // Find the distance between now and the count down date var distance = countDownDate - now; // Time calculations for days, hours, minutes and seconds var days = Math.floor(distance / (1000 * 60 * 60 * 24)); var hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); var minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); var seconds = Math.floor((distance % (1000 * 60)) / 1000); // Display the result in the element with id="demo" $(this).html( days + "d " + hours + "h " + minutes + "m " + seconds + "s " ); // If the count down is finished, write some text if (distance < 0) { clearInterval(x); $(this).html( 'EXPIRED' ); } }, 1000); });
Div markup is (note the data attribute here is dynamic from PHP hence why I need to apply it as an attribute and use that from the JS):
<div class="countdown-element" data-countdown-to="2021-02-10 12:00"></div>'
Advertisement
Answer
The this
inside the setInterval
is callback is not the same this
as inside the .each
Take a copy of this
inside the .each
and use that, eg:
$( '.countdown-element' ).each( function() { var countdownElement = $(this); var timer = setInterval(function() { // ... countdownElement.html(days + "d " + hours + "h " + minutes + "m " + seconds + "s "); // If the count down is finished, write some text if (distance < 0) { clearInterval(timer); countdownElement.html('EXPIRED'); } }, 1000); });
Alternatively, depending on your browser, use =>
to preserve this
into the callback
var i = 1; $("div").each(function() { // => arrow function preserves `this` from outer var timer = setInterval(() => { $(this).html(timer + "," + i) // just a method to break out if (i++>20) clearInterval(timer); }, 100); });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div></div> <div></div> <div></div>