MIrrorMirror MIrrorMirror - 2 months ago 17
Javascript Question

DOM refresh on long running function

I have a button which runs a long running function when it's clicked. Now, while the function is running, I want to change the button text, but I'm having problems in some browsers like Firefox, IE.

html:

<button id="mybutt" class="buttonEnabled" onclick="longrunningfunction();"><span id="myspan">do some work</span></button>


javascript:

function longrunningfunction() {
document.getElementById("myspan").innerHTML = "doing some work";
document.getElementById("mybutt").disabled = true;
document.getElementById("mybutt").className = "buttonDisabled";

//long running task here

document.getElementById("myspan").innerHTML = "done";
}


Now this has problems in firefox and IE, ( in chrome it works ok )

So I thought to put it into a settimeout:

function longrunningfunction() {
document.getElementById("myspan").innerHTML = "doing some work";
document.getElementById("mybutt").disabled = true;
document.getElementById("mybutt").className = "buttonDisabled";

setTimeout(function() {
//long running task here
document.getElementById("myspan").innerHTML = "done";
}, 0);
}


but this doesn't work either for firefox! the button gets disabled, changes colour ( due to the application of the new css ) but the text does not change.

I have to set the time to 50ms instead of just 0ms, in order to make it work ( change the button text ). Now I find this stupid at least. I can understand if it would work with just a 0ms delay, but what would happen in a slower computer? maybe firefox would need 100ms there in the settimeout? it sounds rather stupid. I tried many times, 1ms, 10ms, 20ms...no it won't refresh it. only with 50ms.

So I followed the advice in this topic:

Forcing a DOM refresh in Internet explorer after javascript dom manipulation

so I tried:

function longrunningfunction() {
document.getElementById("myspan").innerHTML = "doing some work";
var a = document.getElementById("mybutt").offsetTop; //force refresh

//long running task here

document.getElementById("myspan").innerHTML = "done";
}


but it doesn't work ( FIREFOX 21). Then i tried:

function longrunningfunction() {
document.getElementById("myspan").innerHTML = "doing some work";
document.getElementById("mybutt").disabled = true;
document.getElementById("mybutt").className = "buttonDisabled";
var a = document.getElementById("mybutt").offsetTop; //force refresh
var b = document.getElementById("myspan").offsetTop; //force refresh
var c = document.getElementById("mybutt").clientHeight; //force refresh
var d = document.getElementById("myspan").clientHeight; //force refresh

setTimeout(function() {
//long running task here
document.getElementById("myspan").innerHTML = "done";
}, 0);
}


I even tried clientHeight instead of offsetTop but nothing. the DOM does not get refreshed.

Can someone offer a reliable solution preferrably non-hacky ?

thanks in advance!

as suggested here i also tried

$('#parentOfElementToBeRedrawn').hide().show();


to no avail

Force DOM redraw/refresh on Chrome/Mac

TL;DR:

looking for a RELIABLE cross-browser method to have a forced DOM refresh WITHOUT the use of setTimeout (preferred solution due to different time intervals needed depending on the type of long running code, browser, computer speed and setTimeout requires anywhere from 50 to 100ms depending on situation)

jsfiddle: http://jsfiddle.net/WsmUh/5/

Answer

SOLVED IT!! No setTimeout()!!!

Tested in Chrome 27.0.1453, Firefox 21.0, Internet 9.0.8112

$("#btn").on("mousedown",function(){
$('#btn').html('working');}).on('mouseup', longFunc);

function longFunc(){
  //Do your long running work here...
   for (i = 1; i<1003332300; i++) {}
  //And on finish....  
   $('#btn').html('done');
}

DEMO HERE!