I'm trying to make a count up timer but the word days doesn't seem to want to show up on the screen
HTML
<div id="countup1">
<div ><span >00</span><span >YRS</span></div> |
<div ><span >00</span><span >DAYS</span></div> |
<div ><span >00</span><span >HRS</span></div> |
<div ><span >00</span><span >MINS</span></div> |
<div ><span >00</span><span >SECS</span></div>
</div>
JS
window.onload = function () {
countUpFromTime("Dec 25, 2021 13:20:00", 'countup1');
};
function countUpFromTime(countFrom, id) {
countFrom = new Date(countFrom).getTime();
var now = new Date(),
countFrom = new Date(countFrom),
timeDifference = (now - countFrom);
var secondsInADay = 60 * 60 * 1000 * 24,
secondsInAHour = 60 * 60 * 1000;
days = Math.floor(timeDifference / (secondsInADay) * 1);
years = Math.floor(days / 365);
if (years > 1) { days = days - (years * 365) }
hours = Math.floor((timeDifference % (secondsInADay)) / (secondsInAHour) * 1);
mins = Math.floor(((timeDifference % (secondsInADay)) % (secondsInAHour)) / (60 * 1000) * 1);
secs = Math.floor((((timeDifference % (secondsInADay)) % (secondsInAHour)) % (60 * 1000)) / 1000 * 1);
var idEl = document.getElementById(id);
idEl.getElementsByClassName('years')[0].innerHTML = years;
idEl.getElementsByClassName('days')[0].innerHTML = days;
idEl.getElementsByClassName('hours')[0].innerHTML = hours;
idEl.getElementsByClassName('minutes')[0].innerHTML = mins;
idEl.getElementsByClassName('seconds')[0].innerHTML = secs;
clearTimeout(countUpFromTime.interval);
countUpFromTime.interval = setTimeout(function () { countUpFromTime(countFrom, id); }, 1000);
}
I've tried doing
<div ><span >00</span><span id="countupDays" >DAYS</span></div>
JS
document.getElementById('countupDays').innerHTML = "DAYS";
to add the word days but that did not work because the timer would stop counting
CodePudding user response:
It's because you had a side effect having the outer element with class days
window.onload = function() {
countUpFromTime("Dec 25, 2021 13:20:00", 'countup1');
};
function countUpFromTime(countFrom, id) {
countFrom = new Date(countFrom).getTime();
var now = new Date(),
countFrom = new Date(countFrom),
timeDifference = (now - countFrom);
var secondsInADay = 60 * 60 * 1000 * 24,
secondsInAHour = 60 * 60 * 1000;
days = Math.floor(timeDifference / (secondsInADay) * 1);
years = Math.floor(days / 365);
if (years > 1) {
days = days - (years * 365)
}
hours = Math.floor((timeDifference % (secondsInADay)) / (secondsInAHour) * 1);
mins = Math.floor(((timeDifference % (secondsInADay)) % (secondsInAHour)) / (60 * 1000) * 1);
secs = Math.floor((((timeDifference % (secondsInADay)) % (secondsInAHour)) % (60 * 1000)) / 1000 * 1);
var idEl = document.getElementById(id);
idEl.getElementsByClassName('years')[0].innerHTML = years;
idEl.getElementsByClassName('days')[0].innerHTML = days;
idEl.getElementsByClassName('hours')[0].innerHTML = hours;
idEl.getElementsByClassName('minutes')[0].innerHTML = mins;
idEl.getElementsByClassName('seconds')[0].innerHTML = secs;
clearTimeout(countUpFromTime.interval);
countUpFromTime.interval = setTimeout(function() {
countUpFromTime(countFrom, id);
}, 1000);
}
<div id="countup1">
<div ><span >00</span><span >YRS</span></div> |
<div ><span >00</span><span >DAYS</span></div> |
<div ><span >00</span><span >HRS</span></div> |
<div ><span >00</span><span >MINS</span></div> |
<div ><span >00</span><span >SECS</span></div>
</div>
CodePudding user response:
The issue is really how you're selecting your elements. Because there are multiple elements with the class days
, using getElementsByClass
is returning multiple elements so idEl.getElementsByClassName('days')[0]
is selecting the div
, not the span
. You could consider removing un-needed classes from your HTML but it's actually perfectly possible to select the correct element with the right selector.
Here is a version that does that (also uses setInterval
instead of setTimeout
to avoid having to manually restart the timeout).
var timeoutId
window.onload = function () {
timeoutId = countUpFromTime("Dec 25, 2021 13:20:00", 'countup1')
};
function countUpFromTime(from, id) {
const secondsInADay = 60 * 60 * 1000 * 24,
secondsInAHour = 60 * 60 * 1000;
const countFrom = new Date(from).getTime();
// The keys of counter are the class names of the spans that should contain the result of the value method
const counter = {
days: (timeDifference) => ( Math.floor(timeDifference / (secondsInADay) * 1) % 365 ),
years: (timeDifference) => Math.floor(Math.floor(timeDifference / (secondsInADay) * 1) / 365),
hours: (timeDifference) => Math.floor((timeDifference % (secondsInADay)) / (secondsInAHour) * 1),
minutes: (timeDifference) => Math.floor(((timeDifference % (secondsInADay)) % (secondsInAHour)) / (60 * 1000) * 1),
seconds: (timeDifference) => Math.floor((((timeDifference % (secondsInADay)) % (secondsInAHour)) % (60 * 1000)) / 1000 * 1)
}
return setInterval( () => {
let now = new Date(),
timeDifference = (now - new Date(countFrom));
for (const [key, value] of Object.entries(counter)) {
document.querySelector(`#${id} span.${key}`).innerHTML = value(timeDifference)
}
}, 1)
}
<body>
<div id="countup1">
<div ><span >00</span><span >YRS</span></div> |
<div ><span >00</span><span >DAYS</span></div> |
<div ><span >00</span><span >HRS</span></div> |
<div ><span >00</span><span >MINS</span></div> |
<div ><span >00</span><span >SECS</span></div>
</div>
You could replace the counter
Object with a Map
and use the result of the selector as the key, but that seems excessively complicated for minor performance gains:
const counter = new Map()
counter.set(document.querySelector(`#${id} span.days`), (timeDifference) => ( Math.floor(timeDifference / (secondsInADay) * 1) % 365 ))
counter.set(document.querySelector(`#${id} span.years`), etc etc
...
for (const [key, value] of counter.entries()) {
key.innerHTML = value(timeDifference)
}