AJAX progress bar

More...

With few lines of JavaScript and CSS you can make a simple AJAX progress bar. JavaScript will periodically ask for progress value and server will respond with XML. Progress value should be extracted from the XML and displayed as width of the DIV element. To start progress bar in this example, please click on the Start button and wait for a second to begin. If you have installed Firebug, open Net tab and watch how this page sends request to the Web server.

More precisely, every 1000ms send_request() function sends request to the server (see setInterval line in polling_start() function). ajax-progress-bar.php returns XML and request_handler() processes received XML. Progress value from XML has meaning of percentage completion of a job.

In the following JavaScript source, please focus to the sending and handling requests. Initialization of the XMLHttpRequest is written in the cross-browser manner and there's nothing more to add. The onreadystatechange property is a function that receives the feedback. It is important to note that the feedback function must be assigned before each send, because upon request completion the onreadystatechange property is reset. This is evident in the Mozilla and Firefox source.

// create XMLHttp request object in a cross-browser manner
initXMLHttpClient = function () {
    var XMLHTTP_IDS,
        xmlhttp,
        success = false,
        i;
    // Mozilla/Chrome/Safari/IE7+ (normal browsers)
    try {
        xmlhttp = new XMLHttpRequest();
    }
    // IE(?!)
    catch (e1) {
        XMLHTTP_IDS = [ 'MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0',
                        'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP' ];
        for (i = 0; i < XMLHTTP_IDS.length && !success; i++) {
            try {
                success = true;
                xmlhttp = new ActiveXObject(XMLHTTP_IDS[i]);
            }
            catch (e2) {}
        }
        if (!success) {
            throw new Error('Unable to create XMLHttpRequest!');
        }
    }
    return xmlhttp;
};

// send request to the server
send_request = function () {
    if (number < number_max) {
        request.open('GET', 'ajax-progress-bar.php', true); // open asynchronus request
        request.onreadystatechange = request_handler;       // set request handler
        request.send(null);                                 // send request
        number++;                                           // increase counter
    }
    else {
        polling_stop();
    }
};

// request handler (started from send_request)
request_handler = function () {
    var level;
    if (request.readyState === 4) {   // if state = 4 (operation is completed)
        if (request.status === 200) { // and the HTTP status is OK
            // get progress from the XML node and set progress bar width and innerHTML
            level = request.responseXML.getElementsByTagName('PROGRESS')[0].firstChild;
            progress.style.width = progress.innerHTML = level.nodeValue + '%';
        }
        else { // if request status is not OK
            progress.style.width = '100%';
            progress.innerHTML = 'Error:[' + request.status + ']' + request.statusText;
        }
    }
};

// button start
polling_start = function () {
    if (!intervalID) {
        // set initial value for current number of requests
        number = 0;
        // start polling
        intervalID = window.setInterval('send_request()', 1000);
    }
};

// button stop
polling_stop = function () {
    // abort current request if status is 1, 2, 3
    // 0: request not initialized
    // 1: server connection established
    // 2: request received
    // 3: processing request
    // 4: request finished and response is ready
    if (0 < request.readyState && request.readyState < 4) {
        request.abort();
    }
    window.clearInterval(intervalID);
    intervalID = false;
    // display 'Demo stopped'
    progress.style.width = '100%';
    progress.innerHTML = 'Demo stopped';
};

Here you can see the source of ajax-progress-bar.php (how is job progress emulated). In your case you will have to calculate percentage of completion and return it in XML format. Caching for ajax-progress-bar.php should be disabled. Many proxies and clients can be forced to disable caching with "header" lines pragma, cache-control and expires.

<?php
// no cache
header('Pragma: no-cache');
// HTTP/1.1
header('Cache-Control: no-cache, must-revalidate');
// date in the past
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
// define XML content type
header('Content-type: text/xml');
// print XML header
print '<?xml version="1.0"?>';
// prepare demo progress value
$progress = (mktime() % 50) * 2;
?>
<DOCUMENT><PROGRESS><?php print $progress ?></PROGRESS></DOCUMENT>

Download source code: redips6.tar.gz

11/21/2010 - Code tested with JSLint & enabled source download
06/10/2011 - Added limit of how many times to request the server (automatic demo stop)

This entry was posted on May 14, 2009 and is filed under JavaScript

Related posts

47 Responses to AJAX progress bar

  1. dbunic says:

    @Sunny - Please, can you give me more details about a problem you mention. Actually, I made tests with Google Chrome 10.0.648.127, FireFox 3.6.10 and IE8 8.0.6001.18702 and in all browsers AJAX progress bar works. Unfortunately I don't have Safari browser to confirm. This demo requests ajax-progress-bar.php every second and displays fetched progress value. Maybe you have some network problem (I'm not kidding) ... I noticed that my other IE8 launched in virtual machine have similar issues. Can you manually access progress-bar.php and test received XML document? Next, try to reload that page and see how progress value is changing. You can also start DOM inspector, choose Network card and click "Start" button. AJAX JavaScript code will send requests and you should see each request line in inspector tool.

    Hope this tips will help you to find and solve the problem.
    Cheers!

  2. gamezat says:

    thank you it's nice
    i will install it to server to server script
    thank you

  3. Andy says:

    Is there a way to get the % finished from another script that is running? I have the page start a big script via xmlhttprequest (and I have a variable in that script defined as to what % it's at), then can I use a 2nd instance of the xmlhttprequest (maybe to another script) to get the percent from the first script somehow?

  4. ARA says:

    I would like to implement progress bar in classic asp. The progress bar will be included to indicate adding record to the database. A user can upload a file with up to 20,000 records. I would like to use this using classic asp. Any chance you can include demo code in asp?

  5. dbunic says:

    @Andy - I'm not sure or even it's not possible to make direct communication between two browsers. But it's possible indirectly. First page should somehow save job progress to the server and other instances should query for percentage. Actually, if you open two browser instances with this demo, both progress bars will show the same value. I know this answer comes late, but hopefully will be helpful to others.

    @ARA - I'm sorry, but my ASP skills are very thin so I can help you with server side only on conceptual level. If you want to create progress bar for database activity, my advice is to split database insert to several steps (simply create loop) . First make one insert with value 0 to the temporary table. When database insert starts, after every 200 inserted rows, update value in temporary table by 1. So, in case of 20,000 rows you will actually get job percentage completion. Now is easy to implement simple service to read updated value from database and return it as XML to the JavaScript progress bar. Hope this tip will give you an idea of how to create progress bar for adding record to the database.

  6. Godly Mathew says:

    @ARA: You can communicate with asp through ajax.

    you can use response.write function.

    eg : response.write("100")

  7. netrevoltech says:

    @dbunic Your solution is exactly what I was thinking of. Its easy to store the progress in database and then send a request to some different page for fetching the progress value from DB with some interval and with a status flag to indicate when to stop sending Ajax request.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>