11
\$\begingroup\$

Instead of using the ProgressBar plugin, this script displays the progress bar for async requests on the page. Could anyone provide any feedback on this, especially if there will be any issues like cross browser compatibility, etc?

<div class="overlay">
    <div class="progress">
       <img src="@Url.Content("~/content/images/loading.gif")" />Loading...
    </div>
</div>

//displays progress bar
$('.overlay').ajaxStart(function () {
       $(this).css({ height: $(document).height(), width: $(document).width() }).show();
       $(this).find(".progress").css({ top: $(window).height() / 2, left: $(window).width() / 2 });
       }).ajaxStop(function () {
       $(this).hide();
});


.overlay
{
    position: fixed !important;
    position: absolute; /*ie6*/
    width: 100%;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    background-color: #000;
    filter: alpha(opacity=20);
    opacity: 0.2;
    -moz-opacity: 0.2;
    -khtml-opacity: 0.2;
    -webkit-opacity: 0.2;
    z-index: 10004;
    display: none;
    filter: progid:DXImageTransform.Microsoft.Alpha(opacity=20); /*ie6*/
}
.overlay .progress
{
    position: absolute;
    z-index: 10005;
    background: #fff;
    color: #000;
}
\$\endgroup\$
  • \$\begingroup\$ There are websites to test browser compatibility; or, you can test across the main browsers yourself, I download safari, opera, firefox, ie 9 and 10 to test websites \$\endgroup\$ – Yvette Colomb Sep 27 '13 at 15:43
  • \$\begingroup\$ Is IE6 still a concern for this project? It is largely considered to be a dead browser, and jQuery's support for older IE versions has been waning. \$\endgroup\$ – cimmanon Dec 6 '13 at 15:01
6
\$\begingroup\$

Realizing that you are trying to make reusable code, I figured I would share my methodology, as I believe it will extend your structure here.

I like to wrap everything into an object with functions appropriate to AJAX, and I added in your .overlay components:

var ajax = {
        showProgressBar:function($overlay){
            var $doc = $(document),
                $win = $(window);

            $overlay
                .css({
                    height:$doc.height(),
                    width:$doc.width(),
                    display:'block'
                })
                .find('.progress')
                .css({
                    top:($win.height() / 2),
                    left:($win.width() / 2)
                });
        },
        hideProgressBar:function($overlay){
            $overlay.hide();
        },
        abortActive:function(){
            var self = this;

            if(($.active > 0) && (self.active !== undefined)){
                self.active.abort();
            }
        },
        clearActive:function(){
            this.active = undefined;
        },
        send:function($type,$url,$data,$success,$error,$abort){
            var self = this,
                $overlay = $('.overlay'),
                $beforeSend = ($abort ? function(){
                    self.abortActive();
                    self.showProgressBar($overlay);
                } : function(){
                    self.showProgressBar($overlay);                        
                }),
                $complete = ($abort ? function(){
                    self.clearActive();
                    self.hideProgressBar($overlay);
                } : function(){
                    self.hideProgressBar($overlay);                        
                }),
                curFunc = $.ajax({
                    type:$type,
                    url:$url,
                    data:$data,
                    beforeSend:$beforeSend
                }).success($success).error($error).complete($complete);

            this.active = ($abort ? curFunc : self.active);
        }
    };

And then it is called with an example of something like this:

ajax.send(
    'POST',
    'requires/submitSomething.php',
    {
        id:$someId,
        type:$someType
    },
    function(data){
        alert('Successful! The response message was: '+data.message);
    },
    function(data){
        alert('Error! The response message was: '+data.message);
    },
    false
);

This is obviously super generic, but should do the trick. A quick explanation:

  • the beforeSend setting will fire a callback function prior to sending the AJAX, which is where you want to load your progress gif
  • the complete setting will fire a callback function once everything else completes, including the success / error functions, so it is where you want to hide the progress gif
  • in the success / error functions, you can include the response data and manipulate as you wish
  • the use of this in the send function refers to the object parent, hence able to see the other functions rather than referring to them by name
  • the ajax call is assigned to a variable to allow for aborting the call mid-stream before starting another (if another action overrides it, for example) ... the reason for the use of this rather than self is because we need to assign it to the object rather than just reference the existing objects within it
  • the function creation is based on the boolean you pass in for $abort, to determine if your AJAX call should stop all current AJAX calls or have it run in parallel (depending on your usage)

And a few small tweaks I made to your existing jQuery code to optimize:

  • cached $(document), $(window), and $('.overlay') as they are used more than once in the functions
  • consolidated your .show() function into the previous CSS statement (as the default is to basically perform a .css({display:'block'}) statement ... if you have overridden this with a custom function, you can return as needed)
  • chained the calls to $('.overlay') and $('.progress'), as they were both based on $(this)

This function should give you a good starting point, and you can modify as needed if you need additional parameters. The only additional parameter I advise against is the use of dataType; for some reason, everyone using json likes to include dataType in their AJAX call (which is an intelligent guess, not a true marker) instead of doing it right. Don't be "that guy", put your appropriate header declaration in the files you are loading via AJAX and it will be bulletproof.

Hope this helped.

\$\endgroup\$
3
\$\begingroup\$

My 2 cents :

  • I definitely learned something today, I didnt know about ajaxStart / ajaxStop, excellent question.

  • In my eyes this should work on most recent browsers, but as Skippy says, you ought to test yourself on every browser.

  • Minor nitpicking, you could remove these from .overlay

top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
width: 100%;

or as per cimmanon remove the resizing in jQuery:

$(this).show();

Which is admittedly more in line with the hiding code.

  • Minor nitpicking but background: #fff; should be background-color: #fff;

All in all, I will definitely borrow your code ;)

\$\endgroup\$
  • \$\begingroup\$ Removing the styles as you suggest makes it not overlay anymore: cssdeck.com/labs/hhyxcw7u. Width can go, but top/right/bottom/left are necessary for the desired effect. \$\endgroup\$ – cimmanon Dec 6 '13 at 14:58
  • \$\begingroup\$ Check this : jsfiddle.net/konijn_gmail_com/8e4Ps your link does not have the jQuery code. \$\endgroup\$ – konijn Dec 6 '13 at 15:21
  • \$\begingroup\$ If anything, setting the width/height via jQuery is redundant (and inefficient), not the CSS. \$\endgroup\$ – cimmanon Dec 6 '13 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.