NafetzD
NafetzD

Reputation: 16

setInterval() method behaves strangely

I have a page with chronometers. I want to update them all in .each() cycle within setInterval() method on every second to animate chronometer. Everything works except that time representation don't get updated.

$(document).ready(function() {
  setInterval(function() {
    $(".chronometer").each(function() {
      var time = parseInt($(this).find("#time").val()) + 1000;
      $(this).html(renderTime(time) + "<input type='hidden' id='time' value='" + time + "'>");
    })
  }, 1000);
});

function renderTime(start) {
  var now = moment().unix() * 1000;
  var duration = moment.duration(now - start).asMilliseconds();
  return humanize(duration);
}

function humanize(ms) {
  days = Math.floor(ms / (24 * 60 * 60 * 1000));
  daysms = ms % (24 * 60 * 60 * 1000);
  hours = Math.floor((daysms) / (60 * 60 * 1000));
  hoursms = ms % (60 * 60 * 1000);
  minutes = Math.floor((hoursms) / (60 * 1000));
  minutesms = ms % (60 * 1000);
  seconds = Math.floor((minutesms) / 1000);
  var rep = days + ":" + hours + ":" + minutes + ":" + seconds;
  return rep;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='chronometer'>
  <input type='hidden' id='time' value='" + full.startDate + "'>
</div>

In debug mode I see that time get updated + 1000, but the result from renderTime(time) function get updated only once. The strange thing for me here is that when i put some breakpoint and go through all steps it get updated but if i stop debugging it isn't, just time input continue incrementing.

I'm sure is some fundamental mistake but i really need to find where it is.

Upvotes: -1

Views: 150

Answers (3)

NafetzD
NafetzD

Reputation: 16

Working code if needed

setInterval(function() {
   $(".chronometer").each(function(){
      var time = parseInt($(this).children(".time").val()) + 1000;
      $(this).html(humanize(time) + "<input type='hidden' class='time' value='" + time + "'>");
   })}
, 1000 );
function calculatePastTime(start) {
var now = new Date().getTime();
var pastTime = now - start;
return pastTime;
}
function humanize(ms) {
days = Math.floor(ms / (24*60*60*1000));
daysms=ms % (24*60*60*1000);
hours = Math.floor((daysms)/(60*60*1000));
hoursms=ms % (60*60*1000);
minutes = Math.floor((hoursms)/(60*1000));
minutesms=ms%(60*1000);
seconds = Math.floor((minutesms)/1000);
var rep = days+":"+hours+":"+minutes+":" + seconds;
return rep;
}

And HTML :

<div class='chronometer'><input type='hidden' class='time' value='" + calculatePastTime(object.startDate) + "'></div>

Everything is in timestamp.

Upvotes: 0

Guffa
Guffa

Reputation: 700322

It seems that you are mixing code from different scripts, there is code to increase the time in the hidden field, and there is code to calculate the time relative to a start time.

You only need one of those, so I commented out the calculation from a start time, as there is no start time set.

You should use a class instead of an id for the hidden field, as you supposedly plan to have multiple chronometers in the page (based on that you are looping them). Using duplicate id:s seems to work at least in some browsers when you scope it like you do, but duplicate id:s generally don't work well at all.

I put an actual value in the hidden field for now, instead of the " + full.startDate + ", that I guess comes from some server code generating the HTML code.

$(document).ready(function() {
  setInterval(function() {
    $(".chronometer").each(function() {
      var time = parseInt($(this).find(".time").val()) + 1000;
      $(this).html(renderTime(time) + "<input type='hidden' class='time' value='" + time + "'>");
    })
  }, 1000);
});

function renderTime(time) {
  //var now = moment().unix() * 1000;
  //var duration = moment.duration(now - start).asMilliseconds();
  return humanize(time);
}

function humanize(ms) {
  days = Math.floor(ms / (24 * 60 * 60 * 1000));
  daysms = ms % (24 * 60 * 60 * 1000);
  hours = Math.floor((daysms) / (60 * 60 * 1000));
  hoursms = ms % (60 * 60 * 1000);
  minutes = Math.floor((hoursms) / (60 * 1000));
  minutesms = ms % (60 * 1000);
  seconds = Math.floor((minutesms) / 1000);
  var rep = days + ":" + hours + ":" + minutes + ":" + seconds;
  return rep;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.6/moment.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='chronometer'>
  <input type='hidden' class='time' value='0'>
</div>
<div class='chronometer'>
  <input type='hidden' class='time' value='1000'>
</div>
<div class='chronometer'>
  <input type='hidden' class='time' value='2000'>
</div>

Upvotes: 2

Neeraj Verma
Neeraj Verma

Reputation: 495

Here is the working example.

$(document).ready(function () {
    setInterval(function () {
      var time = parseInt($("#time").val()) + 1000;
      $(".chronometer").html(renderTime(time));
      $("#time").val(time);
    }, 1000);
});

function renderTime(start) {
    var now = moment().unix();
    var duration = moment.duration(now - start).asMilliseconds();
    return humanize(duration);
}

function humanize(ms) {
    days = Math.floor(ms / (24 * 60 * 60 * 1000));
    daysms = ms % (24 * 60 * 60 * 1000);
    hours = Math.floor((daysms) / (60 * 60 * 1000));
    hoursms = ms % (60 * 60 * 1000);
    minutes = Math.floor((hoursms) / (60 * 1000));
    minutesms = ms % (60 * 1000);
    seconds = Math.floor((minutesms) / 1000);
    var rep = days + ":" + hours + ":" + minutes + ":" + seconds;
    return rep;
}
<script src="http://momentjs.com/downloads/moment.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='chronometer'></div>
<input type='hidden' id='time' value='0'>

Upvotes: 0

Related Questions