Forcing a DOM refresh in Internet explorer after javascript dom manipulation
Asked Answered
C

6

28

Here is the situation. I have some javascript that looks like this:

function onSubmit() {
    doSomeStuff();
    someSpan.style.display="block";
    otherSpan.style.display="none";
    return doLongRunningOperation;
}

When I make this a form submit action, and run it from a non IE browser, it quickly swaps the two spans visibility and run the long javascript operation. If I do this in IE it does not do the swap until after onSubmit() completely returns.

I can force a dom redraw by sticking an alert box in like so:

function onSubmit() {
    doSomeStuff();
    someSpan.style.display="block";
    otherSpan.style.display="none";
    alert("refresh forced");
    return doLongRunningOperation;
}

Also, the obvious jquery refactoring does not affect the IE behavior:

function onSubmit() {
    doSomeStuff();
    $("#someSpan").show();
    $("#otherSpan").hide();
    return doLongRunningOperation;
}

This behavior exists on IE8 and IE6. Is there anyway to force a redraw of the DOM in these browsers?

Commerce answered 9/9, 2009 at 4:7 Comment(3)
Firstly, what are you doing in the longRunningOperation?Relive
Have you tried moving the visibility toggling to its own function?Modification
longRunningOperation is doing form validation. The form is large in a small subset of cases.Commerce
R
2

Can your longRunningOperation be called asynchronously?

Romona answered 9/9, 2009 at 4:49 Comment(2)
You ended up being right, but with some work. I called the long running operation asynchronously, had my submit event return false, and then the async event really submits my form. This lead to proper behavior in all browsers, but took a lot of work and kinda feels kludgy.Commerce
It might feel kludgy, but the best design of the client-side of your app will be one that keeps the browser responsive. When you start long running processes you will hang the browser (big NO!) so it is best to spend the time designing how to manage async operations. Anyways .. have fun!Romona
E
18

Mozilla (maybe IE as well) will cache/delay executing changes to the DOM which affect display, so that it can calculate all the changes at once instead of repeatedly after each and every statement.

To force an update (to force an immediate, synchronous reflow or relayout), your javascript should read a property that's affected by the change, e.g. the location of someSpan and otherSpan.

(This Mozilla implementation detail is mentioned in the video Faster HTML and CSS: Layout Engine Internals for Web Developers.)

Ertha answered 9/9, 2009 at 4:20 Comment(4)
interesting. didn't know this.Relive
I will give that a try in the AM.Commerce
At time 37:15 in the Mozilla video I cited, he suggests asking for "offset top" or "offset left" which require that the layout be up-to-date.Ertha
Thank you sooo much!! This saved me. BTW, the guy doing the video sucks at public speaking.Pickard
H
9

To continue what ChrisW says:

here's flushing script to flash DOM, so you don't have to call alert(""); (found at http://amolnw.wordpress.com/category/programming/javascript/):

function flushThis(id){
   var msie = 'Microsoft Internet Explorer';
   var tmp = 0;
   var elementOnShow = document.getElementById(id);
   if (navigator.appName == msie){
      tmp = elementOnShow.parentNode.offsetTop  +  'px';
   }else{
      tmp = elementOnShow.offsetTop;
   }
}

It works for me!!! Thanks for the tip.

Hogwash answered 24/11, 2010 at 22:12 Comment(0)
A
5

I had this problem in Chrome 21 dragging a word that had a letter with a descender ('g'). It was leaving a trail of moth dust behind on the screen, which would vanish the next time something made the screen refresh. ChrisW's solution (interrogating a layout-sensitive property) didn't work.

What did work was to add a 1-pixel blank div at the top of the page, then remove it a millisecond later, by calling the following the function at the end of the drag operation:

// Needed by Chrome, as of Release 21. Triggers a screen refresh, removing drag garbage.
function cleanDisplay() {
    var c = document.createElement('div');
    c.innerHTML = 'x';
    c.style.visibility = 'hidden';
    c.style.height = '1px';
    document.body.insertBefore(c, document.body.firstChild);
    window.setTimeout(function() {document.body.removeChild(c)}, 1);
}

Note: You need the delay. Simply adding and removing the div doesn't work. Also, the div needs to be added above the part of the page that needs to be redrawn.

Aleenaleetha answered 12/9, 2012 at 20:7 Comment(2)
Was this solution better than just calling the function asynchronously like I did?Commerce
Had a problem with a screen refresh in IE10 and this did the trick, unlike the other ones.Normand
S
3

You can also wrap you longterm function in a setTimeout(function(){longTerm();},1);

Sedgewick answered 25/9, 2009 at 12:18 Comment(0)
R
2

Can your longRunningOperation be called asynchronously?

Romona answered 9/9, 2009 at 4:49 Comment(2)
You ended up being right, but with some work. I called the long running operation asynchronously, had my submit event return false, and then the async event really submits my form. This lead to proper behavior in all browsers, but took a lot of work and kinda feels kludgy.Commerce
It might feel kludgy, but the best design of the client-side of your app will be one that keeps the browser responsive. When you start long running processes you will hang the browser (big NO!) so it is best to spend the time designing how to manage async operations. Anyways .. have fun!Romona
F
2

element.focus() works for me in IE10

function displayOnOff(){
    var elm = document.getElementById("myDiv");
    elm.style.display="block";
    elm.focus();
    for(var i=0; i<1000000; i++){
        console.log("waiting...............");
    }
    elm.style.display = "none";
}
Fearful answered 10/2, 2015 at 9:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.