Search code examples
javascriptthymeleaf

Multiple javascript timers on one page with Thymeleaf generated List


I am struggling with implementing several times on one page.

I made a simple script counting down the time until a certain date, which is different for every div. It all works fine and dandy on one div, but it does not work on others.

The content where it's displayed is a bootstrap card. I do not know how many cards will be on the page since they come as a list, so I can't hard code it.

<div class="row">
<div th:each=" transport : ${transports}">
    <div class="card ml-1 mr-1 mt-3 mb-3 text-center text-primary">
        <figure>
            <div class="card-body">
                <h6 class="card-text"><small class="text-dark font-italic">Time till departure</small></h6>
                <p  class="timer"><small class="text-muted" id="timer">Time till departure</small></p>
            </div>
        </figure>
    </div>
</div>

I know that the problem lies in the id, but how do I dynamically change the id, to it's unique for every card?

I'm using Thymeleaf to generate the template.

I tried to find document.getElementsClassName("timer), but it is nor working.

I'm new to javascript, so I imagine there is best practice to do this, but I did not find the answer.

Thank you for all the tips.

<p  class="timer">
<small class="text-muted" id="timer">
Time till departure
</small></p>
    <script th:inline="javascript">
        const countDownDate = new Date(/*[[${transport.departureDate}]]*/).getTime();

          const x = setInterval(function () {

          const now = new Date().getTime();

          const distance = countDownDate - now;

          onst days = Math.floor(distance / (1000 * 60 * 60 * 24));
          onst hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
          const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
          const seconds = Math.floor((distance % (1000 * 60)) / 1000);

          document.getElementById("timer").innerHTML = days + "d " + hours + "h "
                            + minutes + "m " + seconds + "s ";

          if (distance < 0) {
             clearInterval(x);
             document.getElementById("timer").innerHTML = "EXPIRED";
             }
               }, 1000);
    </script>

Solution

  • Solved by using @lissetrdm solution, but all the values had to be in the function.

    <div th:each=" transport, iterStat : ${transports}">
    <p  class="card-text" th:id="'timer-' + ${iterStat.index}"><small class="text-muted" id="timer">Time till departure</small></p>
    
    
    <script th:inline="javascript">
    
    
    
    
        var x = setInterval(function () {
            var countDownDate = new Date(/*[[${transport.departureDate}]]*/).getTime();
            var index = [[${iterStat.index}]];
    
            console.log(index);
    
            var now = new Date().getTime();
    
            var distance = countDownDate - now;
    
            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);
    
            document.getElementById('timer-'+index).innerHTML = days + "d " + hours + "h "
                + minutes + "m " + seconds + "s ";
            if (distance < 0) {
                clearInterval(x);
                document.getElementById('timer-'+index).innerHTML = "EXPIRED";
            }
        }, 1000);
    </script>