In a loop, innerHTML inserts only the last element called - javascript

I'm trying to display a countdown in several div tags with the same class.
But the problem is that only the last tag of the list contains the countdown.
Here is code:
const contentsDownDate = document.querySelectorAll(".countDown");
nbElement = contentsDownDate.length - 1;
for (var i = 0; i < nbElement; i++) {
var countDownDate = new Date("Jan 5, 2024 15:37:25").getTime();
// Update the count down every 1 second
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);
// Output the result in an element with id="demo"
contentsDownDate[i].innerHTML = days + "d " + hours + "h " +
minutes + "m " + seconds + "s ";
// If the count down is over, write some text
if (distance < 0) {
clearInterval(x);
contentsDownDate[i].innerHTML = "EXPIRED";
}
}, 1000);
}
I did the same thing by calling ids but still the same result, only the last id displays the countdown.
What can I do to solve this problem?
Note that the countdown code is taken from this: w3schools
PS: I also read that innerHTML prints at the end of the loop so it only prints the last tag and so you have to stop/pause the loop to print, especially with setInterval, but I already did it.
Unless this one was to update the countdown time? But in that case where should I place the other setInterval?

The reason why this is not working is because you enter the infinite loop in a blocking state, meaning that the interval is never entered as the browser is busy looping. Imagine the browser can only do one thing at a time, as in a single thread, so the loop is it, and cannot do anything else until it's done, and in your case it never.
Basically, if you put a setInterval() inside loop without clear it then the setInterval never stop and that mean the loop is infinite so it never complete.
Instead of that, put the loop inside the setInterval() will do the job. Let try this:
const contentsDownDate = document.querySelectorAll(".countDown");
nbElement = contentsDownDate.length-1;
var countDownDate = new Date("Jan 5, 2024 15:37:25").getTime();
// Update the count down every 1 second
x = setInterval(function() {
for (i=0; i<=nbElement; i++){
// 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);
// Output the result in an element with id="demo"
contentsDownDate[i].innerHTML = days + "d " + hours + "h "
+ minutes + "m " + seconds + "s ";
// If the count down is over, write some text
if (distance < 0) {
clearInterval(x);
contentsDownDate[i].innerHTML = "EXPIRED";
}
}
}, 1000);

Related

Javascript multiple countdown timers on the same page using dates from django models

this is my first ever post so please let me know if I need to clarify anything thanks.
I don't have any Javascript experience and I'm trying to write a countdown timer that runs through a django model's data and displays a countdown timer based on each individual object date in my database.
My django models work correctly and loops correctly etc.
I place the below script within my django models for loop but the script only pulls the first objects target date and then populates the countdown timer(correctly) for my first django model object's targetdate but it uses the date of only this first model.
My guess is that I need to put the targetdate (the folowing piece of code) :
let targetdate = new Date({{ datemodel.dateinmodel|date:"U" }} * 1000);
also in some sort of for loop within javascript itself. I've tried to do this but I really still struggle a lot with javascript at the moment so I don't have any idea.
Do I need to put the target date also in some sort of loop within my javascript script to be able to make it loop through the rest of the object dates in my django model?
Please find the script that I've got so far below :
<script>
var clockdiv = document.getElementsByClassName("clockdiv");
let targetdate = new Date({{ datemodel.dateinmodel|date:"U" }} * 1000);
document.addEventListener('readystatechange', event => {
if (event.target.readyState === "complete") {
var clockdiv = document.getElementsByClassName("clockdiv");
var countDownDate = new Array();
for (var i = 0; i < clockdiv.length; i++ ) {
countDownDate[i] = new Array();
countDownDate[i]['el'] = clockdiv[i];
countDownDate[i]['time'] = new Date(targetdate).getTime();
countDownDate[i]['days'] = 0;
countDownDate[i]['hours'] = 0;
countDownDate[i]['seconds'] = 0;
countDownDate[i]['minutes'] = 0;
}
var countdownfunction = setInterval(function() {
for (var i = 0; i < countDownDate.length; i++) {
var now = new Date().getTime();
var distance = countDownDate[i]['time'] - now;
countDownDate[i]['days'] = Math.floor(distance / (1000 * 60 * 60 * 24));
countDownDate[i]['hours'] = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
countDownDate[i]['minutes'] = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
countDownDate[i]['seconds'] = Math.floor((distance % (1000 * 60)) / 1000);
if (distance < 0) {
countDownDate[i]['el'].querySelector('.days').innerHTML = 0;
countDownDate[i]['el'].querySelector('.hours').innerHTML = 0;
countDownDate[i]['el'].querySelector('.minutes').innerHTML = 0;
countDownDate[i]['el'].querySelector('.seconds').innerHTML = 0;
}else{
countDownDate[i]['el'].querySelector('.days').innerHTML = countDownDate[i]['days'];
countDownDate[i]['el'].querySelector('.hours').innerHTML = countDownDate[i]['hours'];
countDownDate[i]['el'].querySelector('.minutes').innerHTML = countDownDate[i]['minutes'];
countDownDate[i]['el'].querySelector('.seconds').innerHTML = countDownDate[i]['seconds'];
}
}
}, 1000);
}
});
</script>
<div class="clockdiv" >
<div>
Countdown until target date-
<span class="days"></span>D
<span class="hours"></span>H
<span class="minutes"></span>M
<span class="seconds"></span>S
</div>
</div>
Any guidance on how I should approach this will be appreciated many thanks.
This is not an answer though but I'm facing similar challenge.. I don't know if you've sorted it out. I tried converting the data to JSON using JSON dump with that the whole params comes out for each of the timers. And I see that in my console.log so next challenge is to be able to pass all to the table through a loop I was thinking although it's not conventional but might work. Creating another table close to the main table to move this timer out of the for loop entirely and work from there with it..
This is the link to a solution that worked for me https://stackoverflow.com/a/65218112/16174649
Thanks for the suggestion.
I was unable to get it to work within the Django loop itself so my solution was to seperate and load each date object seperately within the views file in django and then to just build a counter for each date by itself.
Its probably not the most effective solution but it worked as I only had 11 plus dates to build countdowns for.
In the code example below I would simply update/+1 number for the "countDownDate", "date" and "demo" fields until I created 11 scripts for my 11 items so each item/section has its own countdown script.
Below is the first and second script as an example.
<p id="demo"></p>
<script>
{{
let countDownDate = new Date({{ date1.dateinmodel|date:"U" }}*1000).getTime();
// Update the count down every 1 second
let x = setInterval(function() {
// Get today's date and time
let now = new Date().getTime();
// Find the distance between now and the count down date
let distance = countDownDate - now;
// Time calculations for days, hours, minutes and seconds
let days = Math.floor(distance / (1000 * 60 * 60 * 24));
let hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
let minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
let seconds = Math.floor((distance % (1000 * 60)) / 1000);
// Display the result in the element with id="demo"
document.getElementById("demo").innerHTML ="T-" + days + "D " + hours + "H "
+ minutes + "M " + seconds + "S ";
// If the count down is finished, write some text
if (distance < 0) {
clearInterval(x);
document.getElementById("demo").innerHTML = "T- 0D 0H 0M 0S"
;
}
}, 1000);
}}
</script>
<p id="demo2"></p>
<script>
{{
let countDownDate2 = new Date({{ date2.dateinmodel|date:"U" }}*1000).getTime();
// Update the count down every 1 second
let x = setInterval(function() {
// Get today's date and time
let now = new Date().getTime();
// Find the distance between now and the count down date
let distance = countDownDate2 - now;
// Time calculations for days, hours, minutes and seconds
let days = Math.floor(distance / (1000 * 60 * 60 * 24));
let hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
let minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
let seconds = Math.floor((distance % (1000 * 60)) / 1000);
// Display the result in the element with id="demo2"
document.getElementById("demo2").innerHTML ="T- " + days + "D " + hours + "H "
+ minutes + "M " + seconds + "S ";
// If the count down is finished, write some text
if (distance < 0) {
clearInterval(x);
document.getElementById("demo2").innerHTML = "T- 0D 0H 0M 0S"
;
}
}, 1000);
}}
</script>

JS countdown multiple times on page (won't display with getElementsByClassName)

I took some JS code from w3 to create a countdown. (https://www.w3schools.com/howto/howto_js_countdown.asp)
Because I want to display the countdown multiple times on one page I changed the getElementById("demo") to > getElementsByClassName("demo")
Unfortunately, this doesn't work. Nothing shows up. Why is that and how can I display the same counter multiple times? I tried some things but nothing worked out. This is my code:
html
<p class="demo"></p>
js
// Set the date we're counting down to
var countDownDate = new Date("Jan 5, 2022 15:37:25").getTime();
// 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);
// Output the result in an element with id="demo"
document.getElementsByClassName("demo").innerHTML = days + "d " + hours + "h "
+ minutes + "m " + seconds + "s ";
// If the count down is over, write some text
if (distance < 0) {
clearInterval(x);
document.getElementsByClassName("demo").innerHTML = "EXPIRED";
}
}, 1000);
As #ShanieMoonlight mentioned you need to iterate over the HTMLCollection. You can easily do it with minimal adjustments. E.g. when you use the spread-operator the forEach-function will be available.
// Set the date we're counting down to
var countDownDate = new Date("Jan 5, 2022 15:37:25").getTime();
// 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);
// Output the result in an element with id="demo"
[...document.getElementsByClassName("demo")].forEach(e => e.innerHTML = days + "d " + hours + "h "
+ minutes + "m " + seconds + "s ");
// If the count down is over, write some text
if (distance < 0) {
clearInterval(x);
[...document.getElementsByClassName("demo")].forEach(e=>e.innerHTML = "EXPIRED");
}
}, 1000);
<p class="demo"></p>
<p class="demo"></p>
<p class="demo"></p>

How to make double "if" condition in a countdown

I have the following javascript code:
function t5am() {
// Set the date we're counting down to
// Year, Month ( 0 for January ), Day, Hour, Minute, Second, , Milliseconds
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
//:::::::::::: ::::::::::::
//:::::::::::: 5:00 AM ::::::::::::
//:::::::::::: ::::::::::::
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// (AAAA,MM,DD,HH,mm,S));
var countDownDate = new Date(Date.UTC(2020,05,29,12,00,00));
// Update the count down every 1 second
var x = setInterval(function () {
// Get todays date and time
var now = new Date().getTime();
// Find the distance between now an the count down date
// GMT/UTC Adjustment at the end of the function. 0 = GMT/UTC+0; 1 = GMT/UTC+1.
var distance = countDownDate - now - (3600000 * 1);
// 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);
// Output the result in an element with id="demo"
for (const ele of document.getElementsByClassName("t5am")){
ele.innerHTML = (days + "<span>d</span> " + hours + "<span>h</span> "
+ minutes + "<span>m</span> " + seconds + "<span>s</span><br />")
}
// If the count down is over, write some text
if (distance < 0) {
for (const ele of document.getElementsByClassName("t5am")) {
ele.innerHTML = "<p class='live-text'>Live</p> ";
}
if (distance + 7200000 < 0){
ele.innerHTML = "Ended";
}
}
}, 1000);
}
t5am()
It is a counter that works fine for me, but now I want to do a double "if" function.
When the counter reaches zero, then it shows "Started".
I need that in addition to that, after 2 hours after "Started", it shows "Ended"
How can I do it?
This is how you can do this:
Just need add two more hours to your current time which i have done below and then check if distance + twoHours < 0 to show 'Ended' Message
Also, you have to clearInterval(x) as well i will leave that for you to clear when you want after the condition have been met and it is ended.
Remember: Its NOT ideal to use setTimeout for this because if the user leave the page and come page the setTimeout funtion will start from 2 hours again which is not ideal in your case you want to stop it exactly after 2 hours to when its was started which will be in real time regardless of user staying on the browser / screen or not.
Just to make some correction on using innerHTML as well. Its is not rec-emended to user innerHTML at all. I have used textContent which is exactly the same.
InnerHTML is not rec-emended officially by javascript MDN . You can read more about it here: https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML why its not good to use innerHTML to change text in elements.
Recreated Demo: https://jsfiddle.net/bv0odyqr/1/
Try this code and should work just fine.
function t5am() {
// Set the date we're counting down to
// Year, Month ( 0 for January ), Day, Hour, Minute, Second, , Milliseconds
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
//:::::::::::: ::::::::::::
//:::::::::::: #1 ::::::::::::
//:::::::::::: ::::::::::::
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// (AAAA,MM,DD,HH,mm,S));
var countDownDate = new Date(Date.UTC(2020, 05, 27, 20, 20, 0));
// Update the count down every 1 second
var x = setInterval(function() {
// Get todays date and time
var now = new Date().getTime();
const twoHours = new Date();
twoHours.setHours(twoHours.getHours() + 2);
var two = twoHours.getTime()
// Find the distance between now an the count down date
// GMT/UTC Adjustment at the end of the function. 0 = GMT/UTC+0; 1 = GMT/UTC+1.
var distance = countDownDate - now - (3600000 * 1);
//Results div
var result = document.getElementsByClassName("t5am")[0];
// 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);
// Output the result in an element with id="demo"
document.getElementsByClassName("t5am")[0].textContent = days + "<span>d</span> " + hours + "<span>h</span> " +
minutes + "<span>m</span> " + seconds + "<span>s</span><br />";
// If the count down is over, write some text
if (distance < 0) {
result.textContent = "Started";
} else if (distance + twoHours < 0) {
result.textContent = "Ended";
}
}, 1000);
}
t5am()
<div class="t5am"></div>

Custom field calculation in wordpress using Javascript

I have implemented the code below in my site, to display a running timer. The site is running on Wordpress. At the moment the date is input in the code (so it applied site wide). I am looking to have a running timer on each post.
I need to change the code below so that I can use a custom field on each post called "expiry" as the date, instead of the hardwired date below (newDate("Jan 5, 2021 15:37:25).getTime()
<!-- Display the countdown timer in an element -->
<p id="demo"></p>
<script>
// Set the date we're counting down to
var countDownDate = new Date("Jan 5, 2021 15:37:25").getTime();
// 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"
document.getElementById("demo").innerHTML = days + "d " + hours + "h "
+ minutes + "m " + seconds + "s ";
// If the count down is finished, write some text
if (distance < 0) {
clearInterval(x);
document.getElementById("demo").innerHTML = "EXPIRED";
}
}, 1000);
</script>
The above code is sourced from here
My site is here
Thanks in advance
below steps is your requirements:
1) in custom field expiry set return format as custom "F j, Y g:i:s"
example link (https://prnt.sc/pqg79l)
2) add this function in functions.php
function functionname() {
global $post;
$field= get_field('expiry_date', $post->ID);
echo '<input type="hidden" id="date" value="'.$field.'">';
}
add_action( 'template_redirect', 'functionname' );
3) in your js file add below script
var $= jQuery;
var d = $("#date").val();
console.log(d);
// Set the date we're counting down to
var countDownDate = new Date(d).getTime();
// 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"
document.getElementById("demo").innerHTML = days + "d " + hours + "h "
+ minutes + "m " + seconds + "s ";
// If the count down is finished, write some text
if (distance < 0) {
clearInterval(x);
document.getElementById("demo").innerHTML = "EXPIRED";
}
}, 1000);
make sure you have to add <p id="demo"></p> where you want to show in post
I have tried this code..It's totally working fine..I hope i have helped you by this

How to continuously restart countdown when it elapse

I'm using a countdown timer script that I've come across online and modified slightly to suit my website. This works perfectly for counting down to a set date/time but I need the timer to pause for about 1 hour and continue counting for 7 days. For example, when it reaches its end which is Wednesday 00:00:00, it should wait for an hour and then starts counting again till next Wednesday and so on and so fort.
-please i need help!
-here is the code i use
function teus(){
// Set the date we're counting down to
var countDownDate = new Date("Apr 3, 2018 18:00:00").getTime();
// Update the count down every 1 second
var x = setInterval(function() {
// Get todays date and time
var now = new Date().getTime();
// Find the distance between now an 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);
// Output the result in an element with id="demo"
document.getElementById("teu").innerHTML = days + "d " + hours + "h "
+ minutes + "m " + seconds + "s " + "";
// If the count down is over, write some text
if (distance < 0) {
clearInterval(x);
document.getElementById("teu").innerHTML = "Service Time";
}
}, 1000);
}
teus()

Categories

Resources