tags:

views:

12571

answers:

6

hi, i got a client side javascript function which is triggered on a button click (basically, its a calculator!!). Sometimes, due to enormous data on the page, the javascript calculator function take to long & makes the page appear inactive to the user. I was planning to display a transparent div over entire page, maybe with a busy indicator (in the center) till the calculator function ends, so that user waits till process ends.

function CalculateAmountOnClick()
{
  // Display transparent div

  // MY time consuming loop!
    {

    }

  // Remove transparent div 

}

Any ideas on how to go about this? Should i assign a css class to a div (which surrounds my entire page's content) using javascript when my calculator function starts? I tried that but didnt get desired results. Was facing issues with transparency in IE 6. Also how will i show a loading message + image in such a transparent div?

TIA

+1  A: 

I would do somthing like:

1.unhide a div (display:inline)

2.make the position:absolute

3.give it a z-index:99

4.make the height and width 100%

5.when the processing is done set display:none

To make it transparent you'll have to set the opacity which is different in ff ie etc.

To show a loading icon you can always create a second div and position it where you want to on the page. When it's done loading, remove it along with the transparent one.

Kevin
A: 

In addition to all of the above, don't forget to put an invisible iframe behind the shim, so that it shows up above select boxes in IE.

Edit: This site, although it provides a solution to a more complex problem, does cover creating a modal background. http://www.codeproject.com/KB/aspnet/ModalDialogV2.aspx

Chris MacDonald
A: 

For the loading message, I would use a <div> with position:absolute, position it using left and top, and set the display to none.

When you want to show the loading indicator, you're going to have to use a timeout of the div won't display until your processing is done. So, you should modify your code to this:

function showLoadingIncidator()
{
    // Display div by setting display to 'inline'

   setTimeout(CalculateAmountOnClick,0);
}

function CalculateAmountOnClick()
{
  // MY time consuming loop!
    {

    }

  // Remove transparent div 
}

Because you set the timeout, the page will redraw before the time-consuming loop happens.

Joel Anair
+3  A: 

Javacript to show a curtain:

function CalculateAmountOnClick () {
  var curtain = document.body.appendChild( document.createElement('div') );
  curtain.id = "curtain";
  curtain.onkeypress = curtain.onclick = function(){ return false; }
  try {
    // your operations
  }
  finally {
    curtain.parentNode.removeChild( curtain );
  }
}

Your CSS:

#curtain {
  position: fixed;
  _position: absolute;
  z-index: 99;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  _height: expression(document.body.offsetHeight + "px");
  background: url(curtain.png);
  _background: url(curtain.gif);
}

(Move MSIE 6 underscore hacks to conditionally included files as desired.)

You could set this up as add/remove functions for the curtain, or as a wrapper:

function modalProcess( callback ) {
  var ret;
  var curtain = document.body.appendChild( document.createElement('div') );
  curtain.id = "curtain";
  curtain.onkeypress = curtain.onclick = function(){ return false; }
  try {
    ret = callback();
  }
  finally {
    curtain.parentNode.removeChild( curtain );
  }
  return ret;
}

Which you could then call like this:

var result = modalProcess(function(){
  // your operations here
});
Borgar
A: 

i implemented @Borgar suggestions & it worked.... well partially...

i could get a transparent div over my page, but problem was it would appear only if used my mouse scroll!! if i click anywhere on my page or use the browser's scroll bar the browser would appear to hang (things is my javascript is calculating in the background) & once thats done, the browser returns to normal... but in this case the tranperent div doesnt appear...strange!

also can anyone show me some samples/links on how to add a loading indicator with some text in the center of the page over this transparent div, tried without any success ....seems like my CSS skills suck!

update: well seems like my last statement motivated me... i did manage to display a div with an image, its animation didnt work though and i couldnt get it over the transparent div... playing with its z-index too didnt help....

aix
CSS expressions are very bad performance wise
Chris MacDonald
+3  A: 

I'm going to make some heavy assumptions here, but it sounds to me what is happening is that because you are directly locking the browser up with intense processing immediately after having set up the curtain element, the browser never has a chance to draw the curtain.

The browser doesn't redraw every time you update the DOM. It may woit to see if you're doing something more, and then draw what is needed (browsers vary their method for this). So in this case it may be refreshing the display only after it has removed the curtain, or you have forced a redraw by scrolling.

A fair waring: This kind of intense processing isn't very nice of you because it not only locks up your page. Because browsers generally implement only a single Javascript thread for ALL tabs, your processing will lock up all open tabs (= the browser). Also, you run the risk of the execution timeout and browser simply stopping your script (this can be as low as 5 seconds).

Here is a way around that.

If you can break your processing up into smaller chunks you could run it with a timeout (to allow the browser breathing space). Something like this should work:

function processLoop( actionFunc, numTimes, doneFunc ) {
  var i = 0;
  var f = function () {
    if (i < numTimes) {
      actionFunc( i++ );  // closure on i
      setTimeout( f, 10 )
    } 
    else if (doneFunc) { 
      doneFunc();
    }
  };
  f();
}

// add a curtain here
processLoop(function (i){
  // loop code goes in here
  console.log('number: ', i);
}, 
10,  // how many times to run loop
function (){
  // things that happen after the processing is done go here
  console.log('done!');
  // remove curtain here
});

This is essentially a while loop but each iteration of the loop is done in an timed interval so the browser has a bit of time to breathe in between. It will slow down the processing though, and any work done afterwards needs to go into a callback as the loop runs independently of whatwever may follow the call to processLoop.

Another variation on this is to set up the curtain, call your processing function with a setTimeout to allow the browser time to draw the curtain, and then remove it once you're done.

// add a curtain
var curtain = document.body.appendChild( document.createElement('div') );
curtain.id = "curtain";
curtain.onkeypress = curtain.onclick = function(){ return false; }
// delay running processing
setTimeout(function(){
  try {
    // here we go...
    myHeavyProcessingFunction();
  }
  finally {
    // remove the curtain
    curtain.parentNode.removeChild( curtain );
  }
}, 40);

If you are using a js-library, you may want to look at a ready made solution for creating curtains. These should exist for most libraries, here is one for jQuery, and they can help with the CSS.

Borgar