forcing repaint DOM in IE6 and IE7?

61 views
Skip to first unread message

Holts

unread,
Feb 8, 2009, 8:02:06 PM2/8/09
to Prototype & script.aculo.us
I have loop that makes server-side Ajax calls on each iteration, and
returns data. This could be 50 iterations, 500, 5000, whatever. Upon
each iteration, I update that particular row with a server-side
response (i.e. "success" or "fail"), and then update the total count
processed ("26 out of 432 processed"). -- I update the innerHTML of a
div or span, and another div showing the total number of records
processed (at the end of an iteration, or in the onComplete callback
handler of the Ajax.Request). That is all working perfectly fine...
in Firefox, Safari, and every other browser except IE6 and IE7.

I have tried IE hacks such as adding a class to the div, and dropping
a class from the div, adding and dropping child nodes from the div,
etc -- to attempt to force IE to repaint, I have tried waiting a small
interval, to no avail. If you pop up an alert("hai"); at the end of
the iteration, the the IE6 and IE7 DOM will repaint with the updated
values. (btw, how dumb is that?)

Does anybody have any tried and true ways to make IE6 or IE7 repaint a
particular DOM element in these cases (without obviously popping an
alert)? It works flawlessly in Firefox. I know IE is a steaming
pile, but just wondering if anyone has had any success with a hack
that works here.

code here:
http://gist.github.com/57817

it's grabbing all the data properly, so I won't bore you with the
markup... just updating the status of the processing results ...no
effect in IE6 or IE7... doesn't update:

E.g.: won't repaint this until the loop has finished (only in IE):
$('prg_processed').innerHTML = rows_processed;

T.J. Crowder

unread,
Feb 9, 2009, 8:44:47 AM2/9/09
to Prototype & script.aculo.us
Hi,

By marking the ajax requests synchronous, you're basically bringing UI
updates to a screeching halt. :-) Rather than doing a synchronous
loop, how 'bout doing a chained asynchronous loop? E.g., suppose we
have a list (perhaps an Element array from $$) and we want to do a
call to the server for each element, and update its contents based on
the result. Rather than this (pseudo-code):

list.each(function(elm) {
new Ajax.Request(some_url + '?id=' + elm.id, {
asynchronous: false,
onSuccess: function(xport) {
elm.update(...content derived from xport response...);
},
onFailure: function(xport) {
elm.update(ERROR_MESSAGE);
},
onException: function(req, ex) {
elm.update(EXCEPTION_ERROR_MESSAGE);
loopIteration(list, index + 1);
}
});
});

How 'bout this pseudo-code:

loopIteration(list, 0);
function loopIteration(list, index) {
var elm;
if (index < list.length) {
elm = list[index];
new Ajax.Request(some_url + '?id=' + elm.id, {
onSuccess: function(xport) {
elm.update(...content derived from xport
response...);
loopIteration(list, index + 1);
},
onFailure: function(xport) {
elm.update(ERROR_MESSAGE);
loopIteration(list, index + 1);
},
onException: function(req, ex) {
elm.update(EXCEPTION_ERROR_MESSAGE);
loopIteration(list, index + 1);
}
});
}
}

You see how the completion of each asynchronous call triggers the
next; the loop counter and list are maintained in the execution
contexts of the various closures. I did the chaining calls to
loopIteration() separately in the above (rather than in onComplete) in
case failures or exceptions should not continue the loop. If there
are aspects of the page that should be disabled while the loop is
running, you can handle that with a modal flag and disabling relevant
controls during the course of the loop.

There are several advantages to a chained asynchronous loop rather
than a synchronous loop. One of the biggest is that browser can
continue to respond to UI events while the calls are outstanding. Not
only would that solve your painting problem, but it opens up other UI
options, like having a Stop button (with a synchronous loop you could
have it, but the user couldn't click it), or allowing the user to
scroll around in the page while the loop is running, etc. With
synchronous calls, many browsers completely lock up the UI during the
call.

HTH,
--
T.J. Crowder
tj / crowder software / com
Independent Software Engineer, consulting services available

T.J. Crowder

unread,
Feb 9, 2009, 8:48:09 AM2/9/09
to Prototype & script.aculo.us
Hi,

Apologies, copy-and-paste error, that first pseudo-code block should
not have the call to loopIteration in the onException handler.
Corrected pseudo-code for the synchronous loop:

list.each(function(elm) {
new Ajax.Request(some_url + '?id=' + elm.id, {
asynchronous: false,
onSuccess: function(xport) {
elm.update(...content derived from xport response...);
},
onFailure: function(xport) {
elm.update(ERROR_MESSAGE);
},
onException: function(req, ex) {
elm.update(EXCEPTION_ERROR_MESSAGE);
}
});
});

-- T.J. :-)

Mark Holton

unread,
Feb 9, 2009, 11:26:09 AM2/9/09
to prototype-s...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages