Joel DeWitt
Joel DeWitt

Reputation: 1306

HTML progress element not updating

This is a problem I've been struggling with for a while now. I've implemented an HTML5 progress element like so:

      <progress id="progress" value="0" max="100"></progress><output class="percent" id="percent">0</output><span class="prozent">%</span>

Suppose I update the value of progress and percent in a JS loop:

  i = 0;
  pBar = document.getElementById('progress');
  pBar.value = i;//start at 0%
  percent = 1;//set target for next progress bar update in %
  //DO
  do {
    //IF(i > i_max) EXIT
    //CALL VERLET
    VERLET(i, x, v, a, time, const0, gamma, A_o, omega, dt);
    x_plot[i] = [time[i], x[i]];
    v_plot[i] = [time[i], v[i]];
    a_plot[i] = [time[i], a[i]];
    //i = i + 1
    i = i + 1;
    if (parseInt(i / i_max * 100, 10) === percent) {
      pBar.value = percent;//update progress bar
      document.getElementById('percent').innerHTML = percent;
      percent = percent + 1;
    }
  //END DO
  } while (i < i_max);

This is the relevant portion of my script. Please assume all variables are properly declared and initialized, and the script as whole is linted. A draft of the page can be found here.

I don't understand why the values of the progress and output elements are not updated until after the calculation is finished. Or this is what appears to happen. IE11(?) seems to show some updating when initially loading the page, but again doesn't update the progress bar for a new calculation without reloading.

Here is something along similar lines, but not using this modern method. I've taken a stab at getting this example to work, without success. This example, though better written I think, might shed some light on the problem.

Is it a timeout issue? Is there a simple jQuery method I could make use of? Any feedback on this problem will be appreciated.

Upvotes: 1

Views: 1966

Answers (3)

Joel DeWitt
Joel DeWitt

Reputation: 1306

Here's how I got my progress bar to animate:

HTML

<progress id="progress" value="0" max="100"></progress><output class="percent" id="percent">0</output><span class="prozent">%</span>

JS

start = new Date().getTime();
//do stuff
end = new Date().getTime();
t = (end - start);
document.getElementById('progress').value = 0;
document.getElementById('percent').innerHTML = 0;
if (parseInt(t / 100.0, 10) <= 1) {
  t = 1;//minimum update interval in ms
} else {
  t = parseInt(t / 100.0, 10);//actual update interval in ms
}
go = setInterval(animate, t);
value = 0;
max = 100;
go = 0;
function animate() {
  if (value >= max) {
    clearInterval(go);
    return;
  }
  value += 1;
  document.getElementById('progress').value = value;
  document.getElementById('percent').innerHTML = value;
  if (value === max) {
    clearInterval(go);
  }
}

This script can be invoked when the page loads via <body onload="amp()"> or when prompted by the user with <input type="number" name="theta0" id="theta0" value="0.1" min="0.0" max="1.6" step="0.1" onchange="amp()">. As you can see, the update interval is tied to the CPU clock time in ms since I can't update the DOM while in a while loop. It's clunky, but it works.

Upvotes: 0

lante
lante

Reputation: 7336

As @epascarello says, you cant update the DOM in a while loop. Update it with an interval:

var interval = setInterval(function () {
  VERLET(i, x, v, a, time, const0, gamma, A_o, omega, dt);
  x_plot[i] = [time[i], x[i]];
  v_plot[i] = [time[i], v[i]];
  a_plot[i] = [time[i], a[i]];
  i = i + 1;
  if (parseInt(i / i_max * 100, 10) === percent) {
    pBar.value = percent;//update progress bar
    document.getElementById('percent').innerHTML = percent;
    percent = percent + 1;
  }
  if (i < i_max) {
    clearInterval(interval);
  }
}, 100);

Upvotes: 1

Afonso Matos
Afonso Matos

Reputation: 2476

You can't do those kind of operations in a single while-loop.

What happens is the loop will run until it ends and you'll only be able to see the result when it finishes the operation.

For this kind of problems you should go for an asynchronous way.

function updateDom() {
  // do stuff

  setTimeout(updateDom, 500);
}

setTimeout(updateDom, 500);

Upvotes: 1

Related Questions