Link to home
Start Free TrialLog in
Avatar of Mark
Mark

asked on

Can't show processing icon when displayed.

I'm confused. I have the following javascript function, and the absolute DIV show beneath it. The lines of concern are 5, 8 and 19, and 25-27. The rest of the logic is OK, but included for context:

function setState(nme)
{
    var frm = document.zipForm;
    var state = nme.substring(3,nme.length);
    var img = document.getElementById("processing");
    var el = document.getElementsByTagName("input");

    img.style.display = "block";

    for (var i = 0; i < el.length; i++)
    {
        if ((el[i].type == "checkbox") && (el[i].name.indexOf("CT_" + state + "_") == 0))
        {
            el[i].checked = frm.elements[nme].checked;
            setCity(el[i].name);
        }
    }

    img.style.display = "none";
}

:
:

<div id="processing" style="z-index: 1; position: absolute; top: 600px; left: 500px; display: none">
<img style="width: 50px" src="images/processing.gif">
</div>

Open in new window


The image is just one of those animated wheels. You can see it here: https://www.ohprs.org/ohprs/images/processing.gif. When an onclick calls the setState function, I do not see the animation. However, if I put 'alert(img.style.display);' after line 8, it does show the image. But even then, as soon as I click 'OK' the image freezes and ceases to animate. It does disappear after line 19.

Even if I have just some text like "Please Wait" instead of the image, It doesn't show unless I have an alert() after setting the display style.

This must be a relatively common need. What am I doing wrong?
Avatar of Kim Walker
Kim Walker
Flag of United States of America image

It appears that the image div is only displayed while lines 10-17 are processed. Since the input element stored in var "el" doesn't have a length property, the image would appear and disappear in an instant. Certainly faster than your eye can see. If you're trying to use the value of that input element, it would still need to have several million characters in its value in order for the image to remain visible long enough to see.

What is your objective?
OK. I see why "el" would have a length, it holds all input elements. I still believe the cycle would be completed faster than you would be able to see the image. Are you seeing the checkboxes being checked?
@xmediaman: "el" does have a length because it is an array. When "el" is populated it is an array of all the input elements on the page. So he is looping through the input elements to find a checkbox with a specific name? And he wants that processing image to display while that happens.

Since it does probably happen really fast anyway, I would use setTimeout to hide the image and put at least 1000ms as the time for the timeout.

I would try replacing line 19 with
setTimeout('document.getElementById("processing").style.display = "none"',1000);

Open in new window

Avatar of Mark
Mark

ASKER

I'll check out the timeout thing, but cycling through the el does not happen fast. There are over 1000 checkboxes to set/unset. It takes about 15 seconds.
well if the form is that big, when you run that function, is the image in the viewable area? 600 top might not be enough. Absolute positioning is not relative to the visible area.

Try making the image display: block; from the outset and make sure you can see it where you expect to see it.
SOLUTION
Avatar of Tom Beck
Tom Beck
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Mark

ASKER

tommyBoy: Hmmm, I guess I thought animated gifs just "played" on their own. I didn't think the browser needed to run them. Anyway, I used your example as a base and got it to work as shown below. I didn't need the separate checkInput() function. Note that I don't need to show the spinning image if I am collapsing the tree. It visually collapses immediately, even if it is running through the branches and leaves behind the scene for another 15 seconds or so.

jrm213jrm213: > if the form is that big, when you run that function, is the image in the viewable area?

I'm working on that. What I'm trying to do is move the page down as the tree expands using the stateDiv.scrollTop = stateDiv.scrollHeight; statement, but it seems to do nothing at all. All web examples I've seen show this statement. I've verified that my <DIV></DIV> is properly formed and the stateDiv.scrollHeight does have a value -- but the page does not scroll. Any ideas? If this is not a simple question I'll post separately.

function setState(nme)  // nme of the form: ST_OH
{
    var frm = document.zipForm;
    var state = nme.substring(3,nme.length);  // gives: "OH"

    // Show if selected and hidden, or hide if unselected and visible

    if ((frm.elements[nme].checked && document.getElementById("I_" + state).src.indexOf("plus") > 0) ||
        (!frm.elements[nme].checked && document.getElementById("I_" + state).src.indexOf("plus") < 0))
        showByCity(state);

    var el = document.getElementsByTagName("input");

    var stateDiv = document.getElementById(state);     // get <DIV> of target state
    var img = document.getElementById("processing");  // spinning .gif
    var i = 0;

    if (frm.elements[nme].checked) img.style.display = "block";  // don't reveal if hiding cities

    var process = setInterval(function()
    {
        if ((el[i].type == "checkbox") && (el[i].name.indexOf("CT_" + state + "_") == 0)) // if city is in state ...
        {
            el[i].checked = frm.elements[nme].checked;  // set city checkbox to same as state's
            setCity(el[i].name);   // set city's ZIP code checkboxes to same as city's
            stateDiv.scrollTop = stateDiv.scrollHeight;  // attempt to scroll as page expands -- doesn't work
        }

        if (++i >= el.length)
        {
            clearInterval(process);
            img.style.display = "none";
        }
    }, 1);
}

Open in new window

An animated gif is a series of images that the browser displays one after another like a flip book. It requires processing from the browser's rendering engine.

If you want to move the window's scroll position, try scrollTo.

window.scrollTo(0, stateDiv.offsetTop);

I doubt you will see it scroll however. With a 1 millisecond interval, it will never have time to scroll the window before it moves to the next interval. As a test, try changing the interval to 1000 and you may see it scroll. Obviously this will make the process of testing the checkboxes take longer than necessary.

We really have not addressed the basic problem yet. We have managed to get the animated gif to display by using a timer to test the check boxes instead of a for loop. The three fold requirement now is insuring that the gif has time to animate, the current test is complete and the window has time to scroll before moving on to the next test. It's not happening with a 1 millisecond interval. But arbitrarily increasing it is just as bad from a programming standpoint as arbitrarily decreasing it. The whole script needs more work.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Last thoughts:

1.) If you revert back to a regular for loop, the browser's rendering engine will freeze while the loop is iterating. No scrolling, no animation, no images appearing one by one. Then it will suddenly jump to the bottom with all images showing up at once. The interval is there to make it appear that multiple processes are executing simultaneously. That's my prediction.

2.) It's great that it's working for you in your testing. The way I look at it however, the 1 millisecond is an arbitrary number with no bearing in time on the actual processes you are calling for each interval. Think about it. You say the checkbox checking takes 15 seconds to do over a thousand in a regular for loop. Let's say you have 1,200 checkboxes. That means 12.5 milliseconds to process each. You have the interval set to 1 millisecond so the looping is done and the interval cleared after 1,200 milliseconds, 1.2 seconds. See the discrepancy? 15 seconds is 15,000 milliseconds. What is happening for the other 13,800 milliseconds? Is the browser engine playing catch up? Does it have all those images and scrollTo commands backed up in memory waiting to barf them up...or CRASH!? There has to be a better way to write this so the interval keeps chugging away until each checkbox is actually processed instead of just stopping when the interval count equals the checkbox count. I guess I'm concerned about unpredictable results in a real world setting. What happens when it's run on a different browser or an older browser or a slower computer?
Avatar of Mark

ASKER

> If you revert back to a regular for loop, the browser's rendering engine will freeze while the loop is iterating. ... That's my prediction.

You're probably right. I'm not in a hurry to test this, but I probably will, just to satisfy my own curiosity. I'll post back the results if/when I do that.

> The way I look at it however, the 1 millisecond is an arbitrary number with no bearing in time on the actual processes you are calling for each interval. ...

Well, there are a little over 1,000 checkboxes to process in the largest state (OH). It sets a checkbox on each interval, so that's 1 millisecond per checkbox, not 1,000ms for *each* checkbox. In fact, the whole thing takes 50 seconds versus the original 15 seconds. That's acceptable because I know the user got impatient when nothing happened in the 15 seconds, but seeing boxes expand on the screen in live time is more reassuring, even though the total time is longer. At optimum, the time should be the original 15 seconds, plus the 1000ms for the intervals. The actual time reflects the browsers time to expand the divs, so I think even if having no interval worked, it probably wouldn't make much visual difference.

Probably the best way to handle this is using AJAX and show a progress bar zipping across in 15 seconds.
Avatar of Mark

ASKER

Well, I felt the need to try w/o the 1ms interval. I replaced the "var process = setInterval(function()" by the following:

   for (var i = 0; i < el.length; i++)
    {
        if ((el[i].type == "checkbox") && (el[i].name.indexOf("CT_" + state + "_") == 0))
        {
            stateFound = true;
            el[i].checked = frm.elements[nme].checked;
            setCity(el[i].name);
            window.scrollTo(0, (stateDiv.scrollHeight - initHeight) + stateDiv.offsetTop);
        }
        else if (stateFound && (el[i].type == "checkbox") && (el[i].name.indexOf("CT_") == 0))
            break;   // moved to next state, finished
    }

    img.style.display = "none";

Open in new window

This does appear to expand the hidden div's faster than the 1ms interval, but expansion visually stopped after 3-4 seconds (as you predicted). Any attempt to scroll or otherwise manipulate the page gave the status message, "mydom.org is not responding due to a long-running script." After a total of 43 seconds, control returned and the rest of the div's appeared in expanded form.

As I thought, actual exansion of the div's takes the most time: 43 seconds. This means the the 1ms interval only adds an additional 7 seconds to the 50 second total div expansion time. This is acceptable. The user will wait patiently for 50 seconds as long as something is happening on-screen. Without expanding the city div's on-screen, the user will not be patient for the actual 15 seconds it takes to check all boxes with no visual feedback.

I could probably save lots of time by just showing the spinning "processing" image and not expand the div's, which should only take 7s (interval) + 15s (checkbox time) = 22 secs. However it is unlikely in actual practice using this application that anyone will select and entire state at a time and it is otherwise nice for the user to see the expanded selection at the city/zip level.

Thanks for the setInterval() idea. That did the trick. I'm calling this one done.
Avatar of Mark

ASKER

I list the complete solution in my post based on tommyboy's idea