skip to Main Content

I have page where there are multiple timers.

Each match has different timers. They start when the match is being completed. When the user clicks on complete match button the match status is being changed to complete and the timers start based on start and end time received from the ajax request. So the problem I am facing here is when a match is being completed the first timer is running perfectly fine, but the 2nd, 3rd and so on should be running based on their own timers as their time slabs are different. But as of now all timers are the same as the first one.

I’m not sure what is wrong. Surprisingly, when I refresh the page it works fine as of the time is predefined using php but as soon as the timer runs on click of the button it conflicts until I refresh the page

  1. Run multiple timers on single page
  2. The countdown only starts when user clicks button of relative row and the start time and end time is being received via ajax request as soon as request completes the timer starts based on start and end time received from the server

Problem :
Timer runs but it conflicts with other timers as it replaces with the countdown of the first row

$(function(){
    function renderCountdown(setClass, setID) {
      // Logs 
      let days, hours, minutes, seconds; // variables for time units
      let count = 0;
      var getCountdown = function (c) {
          if (setClass == 'true') {
              var timeStart = $('#match-row-info-' + setID + ' input[name=timeStart]').val();
              var dateTime = $('#match-row-info-' + setID + ' input[name=matchTimeEnd]').val();
          }

          var dateStart = new Date(timeStart);
          var dateEnd = new Date(dateTime);
          let currentDate = dateStart.getTime();
          let targetDate = dateEnd.getTime(); // set the countdown date
          // find the amount of "seconds" between now and target
          let secondsLeft = ((targetDate - currentDate) / 1000) - c;
          days = pad(Math.floor(secondsLeft / 86400));
          secondsLeft %= 86400;
          hours = pad(Math.floor(secondsLeft / 3600));
          secondsLeft %= 3600;
          minutes = pad(Math.floor(secondsLeft / 60));
          seconds = pad(Math.floor(secondsLeft % 60));
          // format countdown string + set tag value
          var clockData = hours + ':' + minutes + ':' + seconds;

          if (setClass == 'true') {
              clockDiv  = '#match-row-info-' + setID + ' .match-timer';
              targetDiv = '#match-row-info-' + setID;
          } 

          if (hours <= '00' && minutes <= '00' && seconds <= '00') {
              clockData = '00:00:00';
              var clockDiv;
              var targetDiv;

              if (setClass == 'true') {
                  var matchStatus = $('#match-row-info-' + setID + ' input[name=matchStatus]').val();

                  if (matchStatus == 3 && seconds == '00') {
                      if(!$('#match-row-info-' + setID + ' .match-timer').hasClass('pause-clock')) {
                          //Additional function after time is compelted
                      }
                  }                
              } 
          }

          if ($(targetDiv + ' input[name=matchTimeEnd]').val() == '') {
              clockData = '00:00:00';
          }

          $(clockDiv).html(clockData);
      }

      function pad(n) {
          return (n < 10 ? '0' : '') + n;
      }

      getCountdown();

      setInterval(function () {
            getCountdown(count++);
      }, 1000);
  }

if ($('.multi-match-timer').length > 0) {
  $('.multi-match-timer').each(function () {
    var setID = $(this).children('input[name=matchRowID]').val();
    renderCountdown('true', setID);
  });
}

function AddMinutesToDate(date, minutes) {
     return new Date(date.getTime() + minutes*60000);
}

function DateFormat(date){
var monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
  var days = date.getDate();
  var year = date.getFullYear();
  var month = (date.getMonth()+1);
  var hours = date.getHours();
  var minutes = date.getMinutes();
  var seconds = date.getSeconds();
  minutes = minutes < 10 ? '0' + minutes : minutes;
  var strTime = monthNames[(month - 1)] + ' ' + days + ', ' + year + '/ '+hours + ':' + minutes + ':' + seconds;
  return strTime;
}


  setTimeout(function () {
        var now = new Date();
        var next = AddMinutesToDate(now,5);
        $('#match-row-info-383 input[name=timeStart]').val(DateFormat(now));
        $('#match-row-info-383 input[name=matchTimeEnd]').val(DateFormat(next));
        $('#match-row-info-383 input[name=matchStatus]').val(3);
  }, 3000);
  
  setTimeout(function () {
        var now = new Date();
        var next = AddMinutesToDate(now,5);
        $('#match-row-info-385 input[name=timeStart]').val(DateFormat(now));
        $('#match-row-info-385 input[name=matchTimeEnd]').val(DateFormat(next));
        $('#match-row-info-385 input[name=matchStatus]').val(3);
  }, 6000);
}); 
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

<div id="match-row-info-383">
  <div class="match-timer-box multi-match-timer">
    <input type="hidden" name="timeStart" value="">
    <input type="hidden" name="matchTimeEnd" value="">
    <input type="hidden" name="matchRowID" value="383">
    <input type="hidden" name="matchStatus" value="2">
    <span class="match-timer ">00:00:00</span>
  </div>
</div>

<div id="match-row-info-384">
  <div class="match-timer-box multi-match-timer">
    <input type="hidden" name="timeStart" value="">
    <input type="hidden" name="matchTimeEnd" value="">
    <input type="hidden" name="matchRowID" value="384">
    <input type="hidden" name="matchStatus" value="2">
    <span class="match-timer ">00:00:00</span>
  </div>
</div>

<div id="match-row-info-385">
  <div class="match-timer-box multi-match-timer">
    <input type="hidden" name="timeStart" value="">
    <input type="hidden" name="matchTimeEnd" value="">
    <input type="hidden" name="matchRowID" value="385">
    <input type="hidden" name="matchStatus" value="2">
    <span class="match-timer ">00:00:00</span>
  </div>
</div>

you will notice all 3 timers have different time start and time end but still they are same there is some confliction in it

for example

match 1 ended
00:05:00 time should run here

match 2 pending
00:00:00 this match should not run any timer

match 3 ended
00:04:30 but this timer is being running as same for match 1

but when i refresh the page it works fine as the timer starts on click of button can anyone help me out

2

Answers


  1. Chosen as BEST ANSWER

    I figured out by my self after long research on every ajax call I do have to run the function again in order to start timer to run according to time assigned to each row there fore initially have to set start time as blank and check if the start time is empty do not run function for particular div so when ever ajax call is made run the function at that time but if there is any one who can also suggest me if this approach is wrong or is it correct. so this is what i did

    if ($('.multi-match-timer').length > 0) {
      $('.multi-match-timer').each(function () {
          var setID = $(this).children('input[name=matchRowID]').val();
    
          /*only run the function if start time is predefined*/
          if($(this).children('input[name=timeStart]').val() != '') {
            renderCountdown('true', setID);
          }
      });
    }
    

    So when ever ajax call is made and it is the time to start the timer for a particular row run function at that time

    $.ajax({
            url: $(this).attr('href'),
            type: 'POST',
            dataType: 'json',
            success: function (response) {
                renderCountdown('true', response.rowID);
            }
        });
    

  2. Rather than having a bunch of anonymous global timers going on in the background, you can store the timer as a property of the element that is displaying that timer.

    Here is an example that uses manual buttons, but you could trigger any of these events programmatically via an ajax callback as well.

    Couple of other things to note about timers:

    • 1000 doesn’t mean 1 second exactly, it means anytime after 1000 milliseconds. Depending on what else the client is doing, you can get significantly longer delays than expected, so don’t use intervals / timeouts for super time sensitive things.

    • browsers can put the javascript event loop to sleep (say if a user is on mobile and the display shuts off). This will stop any interval / timeout. The workaround is to take timestamps, and then compute the difference to get the real time elapsed. It’s a few extra steps that you may or may not need to consider.

    $('.match')
      .on('click', 'button[data-action="start"]', function() {
        let parent = $(this).parent()[0]; //use the element itself, not a jQuery object of it
        parent.time_elapsed ??= 0; //initialize values if necessary
        parent.timer ??= null; //can be undefined or int, we explicitly want null for not active
        
        if (parent.timer === null) {
          parent.timer = setInterval(function() {
            parent.time_elapsed++;
            $(parent).trigger('update_display');        
          }, 1000);
        }
      })
      .on('click', 'button[data-action="stop"], button[data-action="reset"]', function() {
        let parent = $(this).parent()[0];
        clearInterval(parent.timer);
        parent.timer = null; //clearInterval doesnt do this
        
        if (this.dataset.action === 'reset') {
          parent.time_elapsed = 0;
          $(parent).trigger('update_display');
        }
      })
      .on('update_display', function() {
        $(this).find('.display').text([
            this.time_elapsed / 3600,
            this.time_elapsed / 60,
            this.time_elapsed % 60
          ].map((t) => ('0' + Math.floor(t)).substr(-2)).join(':'));
      });
    .match{
      display: grid;
      gap: 1rem;
      grid-template-columns: 4rem repeat(3, 3rem);
      margin: 1rem 0;}
    <div id="38" class="match">
      <span class="display">00:00:00</span>
      <button data-action="start">start</button>
      <button data-action="stop">stop</button>
      <button data-action="reset">reset</button>
    </div>
    <div id="39" class="match">
      <span class="display">00:00:00</span>
      <button data-action="start">start</button>
      <button data-action="stop">stop</button>
      <button data-action="reset">reset</button>
    </div>
    <div id="40" class="match">
      <span class="display">00:00:00</span>
      <button data-action="start">start</button>
      <button data-action="stop">stop</button>
      <button data-action="reset">reset</button>
    </div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search