1

I have a web page that displays todo lists as seperate div's/segments. On each todo item is a countdown clock controlled by JavaScript. I can have multiple items in my todo list and would like multiple countdown clocks (one for each item)

The JS runs correctly for the first item in the list but not multiple items. If I delete the first item with a countdown clock then the second item's clock shows and starts counting down.

How can I make use of the same script for each item in my todo list?

Can I turn it into a function that is called within my loop passing the ID? I have tried this but can't get it to work.

My best example is simplified below.

{% for todo in todo_list}

// div sections (each section should have its own independent countdown timer)

<div id="segment/{{todo.id}}">
<div id="diff-{{todo.id}}">

// JavaScript inside for loop
// Script to run for each item in todo list and update the div with time/expired based on the todo.id

<script>
var diff = document.getElementById('diff-{{todo.id}}');
var now = moment.utc().format("YYYY-MM-DD HH:mm:ss");
var input_time = '{{todo.created_on}}';
var exam_end_time ='{{todo.eta}}'
var mins = moment.utc(moment(exam_end_time, "HH:mm"),diff(moment(now, "HH:mm"))).format("mm")
var frequency = mins*60
var refreshIntervalId = setInterval(() => {
   const formatted = moment.utc(frequency--*1000.format("mm:ss");
      diff.innerHTML = formatted;
}, 1000;

setTimeout(() => {
   if(mins === ) {
      diff.innerHTML = "Expired";
      clearInterval(refreshIntervalId);
}},frequency*1000;
</script>
</div>
</div>

{% endfor %}
luke jon
  • 201
  • 2
  • 10
  • 1
    Try putting each ` – ggorlen Jul 15 '22 at 00:24
  • 1
    Have you inspected the HTML that gets rendered from your code? If you view it in you browser developer tools you see that you've generated the JS multiple times. Which means you'd be trying to overwrite your variables. You need to extract your JS out into it's own function and call it for each item in your list. – PGHE Jul 15 '22 at 02:07
  • Thank you for the advice. I have amended the typo. What you have both said is what I am seeing in my browser. I agree I need to extract it out into a seperate function but when I try that it doesn't run for any of the items. If I put the contents of – luke jon Jul 15 '22 at 02:46
  • Hey @ggorlen wrapping the script inside IIFE closure did the trick! Thank you both – luke jon Jul 15 '22 at 03:28
  • 1
    Glad to hear. Feel free to write a [self-answer](https://stackoverflow.com/help/self-answer). By the way, `setTimeout(() => {}, 1000)` doesn't accurately count seconds; not sure how much you care about that. See [this](https://stackoverflow.com/questions/21097421/what-is-the-reason-javascript-settimeout-is-so-inaccurate) – ggorlen Jul 15 '22 at 03:31
  • I am just looking at that now. It does countdown in seconds but if I refresh the page it starts at the nearest minute which isnt good. Will wring a self answer now! Thanks again – luke jon Jul 15 '22 at 03:37
  • https://stackoverflow.com/questions/29971898/how-to-create-an-accurate-timer-in-javascript - looking at this now, thanks for the warning! – luke jon Jul 15 '22 at 03:44

1 Answers1

0

Found solution with thanks to help from the board. Wrapped script within IIFE as shown below.

{% for todo in todo_list}

  // div sections (each section should have its own independent countdown timer)

  <div id="segment/{{todo.id}}">
    <div id="diff-{{todo.id}}">

      // JavaScript inside for loop
      // Script to run for each item in todo list and update the div with time/expired based on the todo.id

      <script>
        (function timer() {
          var diff = document.getElementById('diff-{{todo.id}}');
          var now = moment.utc().format("YYYY-MM-DD HH:mm:ss");
          var input_time = '{{todo.created_on}}';
          var exam_end_time ='{{todo.eta}}'
          var mins = moment.utc(moment(exam_end_time, "HH:mm"),diff(moment(now, "HH:mm"))).format("mm")
          var frequency = mins*60
          var refreshIntervalId = setInterval(() => {
            const formatted = moment.utc(frequency--*1000.format("mm:ss");
            diff.innerHTML = formatted;
          }, 1000;

          setTimeout(() => {
            if (mins === ) {
              diff.innerHTML = "Expired";
              clearInterval(refreshIntervalId);
            }
          },frequency*1000;
        })()
      </script>

    </div>
  </div>
{% endfor %}
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
luke jon
  • 201
  • 2
  • 10