Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

A jQuery Client Status Bar


:P
On this page:

Several people have asked about the status bar in my jQuery Photoalbum example I posted recently. This is nothing fancy at all and actually quite simple to do, but since several people have asked me I thought I'd discuss how it works. Although this solution uses jQuery it's easy enough to do something similar with plain DOM code or another JavaScript library - most of what makes this work is really CSS (and I suspect that's what some of the questions were really about), rather than any sort of client code, although the component I'll show at the end is a little more involved.

Why a Status Bar?

I find myself using Statusbars for information display in most of my administration pages and on occasion also in some main site front end pages. Like in desktop apps, once you start doing client side scripting using alert boxes for information gets to be a painful user interface practice and it's practical to use some consistent location to display all messages. For this task I like status bars either at the top or bottom of the page.

In the photo album application the status bar is used on the bottom of the page using fixed placement with some transparency so that the status bar is always visible but floats on top of all content:

StatusBar

When messages are sent to status bar they can be timed out so that the status bar reverts back to some default message (Ready typically). When a new message is assigned it's displayed in highlighted format:

StatusBarHighlight 

After the timeout is up the display reverts back the plain black and white formatting or rather the default styling defined via the statusbar CSS class.

You can see the status bar running in the sample photo album page:

http://www.west-wind.com/rick/photoalbum/demoMaui2006/default.aspx?Admin=true

Saving Changes and deleting images causes updates of the status bar (as well as any Ajax callback errors which hopefully shouldn't occur <g>).

Starting with CSS

What makes this work for the most part is CSS styling of the element. The statusbar is little more than a simple <div> tag with a CSS class applied. There are two classes that are used for the basic display; one for the base display and one for the highlight display that is used when a timeout is applied:

.statusbar
{
    position: fixed;
    bottom: 5px;
    left: 0px;
    right: 0px;
    height: 16px;    
    padding: 5px;
 
    background: black;
    color: white;    
    border: solid 1px lightgray;
 
    opacity: .70;    
    filter: alpha(opacity="70");
    z-index: 200;
 
    overflow: hidden;
    overflow-y: auto; 
}
.statusbarhighlight
{
    font-weight: bold;
    background-color: khaki;
    color: Maroon;
    border: solid 1px silver;
}

The key thing for the statusbar is the fixed positioning which puts the status bar on the bottom of the page and keeps it there regardless of scrolling the browser. I like to bump the status bar 5px above the window bottom and then use transparency to let the underlying content seep through, because any other content will flow underneath it. Unless you use a statusbar in a fixed container of some sort, I think this is a good idea to make it clear the status bar sits on top of content rather than denoting the absolute bottom of the page.

The highlight will be applied in addition to the statusbar class so the display for highlights effectively combines both styles. The highlight merely changes colors and border to highlight the statusbar text before the highlight is removed after a short timeout.

You can obviously change the CSS any way you like since it's only CSS so you can make the status bar display a square box rather than a strip on the bottom, or a bar running vertically down the right side. And that's the point anything goes.

Basic JavaScript jQuery Code

When I originally built the statusbar I just used a generic function that is quick and dirty. It basically creates a DOM element for the status bar on the fly and applies the appropriate classes. The function is very basic and hard codes a few things:

function showStatus(message,timeout,add)
{        
    if (typeof _statusbar == "undefined")
    {
       // ** Create a new statusbar instance as a global object
        _statusbar = 
            $("<div id='_statusbar' class='statusbar'></div>")
                    .appendTo(document.body)                   
                    .show();
    }
 
    if (add)              
       // *** add before the first item    
        _statusbar.prepend( "<div style='margin-bottom: 2px;' >" + message + "</div>")[0].focus();
    else    
        _statusbar.text(message)
 
    _statusbar.show();        
 
    if (timeout)
    {
        _statusbar.addClass("statusbarhighlight");
        setTimeout( function() { _statusbar.removeClass("statusbarhighlight"); },timeout);
    }                
}

With this function and the above CSS in place you can now from anywhere in your code issue:

showStatus("Photo Collection has been updated",5000);

Notice that there's also an add parameter which allows for cumulative entries where the data is added to the top of the div tag. This is useful if you want to use the status bar for outputting debugging messages and keep the list visible. For this to work you'd probably want to bump the height of the .statusbar class to 40px or bigger to see a few of the messages along with the scrollbars that let you scroll the list.

Note that you have a fair bit of control over where the statusbar goes and what it looks like via CSS. The dependency in this code is basically that a _statusbar global variable gets created and that you have to have .statusbar and .statusbarhighlight styles for the display to show the statusbar appropriately.

A more generic Statusbar Component

The basic code is OK and self contained, but it might be better to build a more generic component. Mind you this the following is a first cut. I haven't really gone through cleaning this code up or thought much about following the jQuery guidelines for plug-ins because in effect I prefer this to be callable via a single function, plus a single call for setup rather than as a jQuery utility function. In this sense this component is a little different than a typical jQuery plugin because it doesn't apply against a matched set of jQuery objects.

The generic version I built is basically a single class with a couple of methods. The idea is that you create an instance of the class somewhere in your startup code to configure it:

_statusbar = new StatusBar("#divStatus",
                           {showCloseButton: true, 
                            additive: true,
                            afterTimeoutText: "Click on caption to edit text..."});

from then on you can either use:

_statusbar.show("Images have been reloaded",5000);      
showStatus("Photo Collection has been updated",5000);

The latter is a utility function created that simply wraps the class by creating a global _statusbar variable using the default constructor and working off that. This is useful as it allows calling the function without any set up at all.

There's a bit more to this component in terms of configuration via properties. In jQuery fashion any of the properties can be optionally passed in via a options object map that defines any of the StatusBar properties to configure. For example, in the above I set three properties to allow the status bar to be closed, to show message additively so that there's a message history displayed and to have the text revert to a fixed caption after a timeout has fired.

Here's the source for the StatusBar object:

function StatusBar(sel,options)
{
    var _I = this;       
    var _sb = null;
 
    // options    
    this.elementId = "_showstatus";
    this.prependMultiline = true;   
    this.showCloseButton = false; 
    this.afterTimeoutText = null;
 
    this.cssClass = "statusbar";
    this.highlightClass = "statusbarhighlight";
    this.errorClass = "statuserror";
    this.closeButtonClass = "statusbarclose";
    this.additive = false;   
 
    $.extend(this,options);
 
    if (sel)
      _sb = $(sel);
 
    // create statusbar object manually
    if (!_sb)
    {
        _sb = $("<div id='_statusbar' class='" + _I.cssClass + "'>" +
                "<div class='" + _I.closeButtonClass +  "'>" +
                (_I.showCloseButton ? " X </div></div>" : "") )
                .appendTo(document.body)                   
                .show();
    }
    if (_I.showCloseButton)
        $("." + _I.cssClass).click(function(e) { $(_sb).hide(); });
 
 
    this.show = function(message,timeout,isError)
    {            
        if (_I.additive)       
        {
            var html = "<div style='margin-bottom: 2px;' >" + message + "</div>";
            if (_I.prependMultiline)
                _sb.prepend(html);
            else
                _sb.append(html);            
        }
        else
        {
 
            if (!_I.showCloseButton)    
                _sb.text(message);
            else
            {            
                var t = _sb.find("div.statusbarclose");                
                _sb.text(message).prepend(t);
            }
        }               
 
        _sb.show();        
 
        if (timeout)
        {
            if (isError)
                _sb.addClass(_I.errorClass);
            else
                _sb.addClass(_I.highlightClass);
 
            setTimeout( 
                function() {
                    _sb.removeClass(_I.highlightClass); 
                    if (_I.afterTimeoutText)
                       _I.show(_I.afterTimeoutText);
                },
                timeout);
        }                
    }  
    this.release = function()
    {
        if(_statusbar)
            $(_statusbar).remove();
    }       
}
// use this as a global instance to customize constructor
// or do nothing and get a default status bar
var _statusbar = null;
function showStatus(message,timeout,additive,isError)
{
    if (!_statusbar)
        _statusbar = new StatusBar();
    _statusbar.show(message,timeout,additive,isError);
}

The class provides the implementation and an optional static _statusbar instance is created to allow easy access to the object. If you don't you can use the showStatus() function implemented below which creates a default instance of the status bar and makes it work. Assuming you have styles configured for statusbar and statushighlight you'll get a status bar displayed according to your styling.

showStatus("Updated photo settings.",5000);

If you want to customize you can set the _statusbar instance explicitly using the configured constructor. Using the constructor allows you to override a few behaviors and it gives you a few more options in how the status bar displays:

  • Multi-line status display
  • Additive status messages with messages added top or bottom
  • Show an optional close 'button'
  • Ability to use custom CSS classes

To set this up you'd do the following in page startup code:

$(document).ready( function() {        
    if (serverVars.adminMode) 
    {        
        MakeListEditable();   
 
        var status = "Click on caption to edit text. Drag image to sort list..."
        _statusbar = new StatusBar(null,{showCloseButton: true, 
                                        additive:true,
                                        afterTimeoutText: status });
        _statusbar.show(status);      
    }            
} );     

You can pass options for customizing each of the StatusBar's properties using typical jQuery.extend() functionality where you can pass an object map of any of the StatusBar properties you want to override in the options parameter.

The additive feature allows you to display muliple status messages with messages appended to either the top or bottom (using the prependMultiline property). This allows for using the status bar as a debugging tool as well so you can write out status messages and avoid using alert() boxes as well. Here's what this looks like:

Multiline

You can have multiple status bars in a page as long as you create and hold on to multiple instances of the StatusBar object. For example you can have a display status bar and a debug status bar and even style them differently. A debug type output bar might be better served as a vertical bar on the left or right side of the browser for example and to do this you'd probably want to customize the CSS.

Note there are a few other components out there that provide debug output and if you are looking for some trace type output tool to help with debugging you're probably better off using one of these jQuery plug-ins. But if you're looking for a quick and dirty way to dump out messages to the screen in application or even library code the above approach works well because it can be done simply by adding a line of code with no further setup including in library code as long as the script is loaded.

From the Server side

Several people also asked how you can drive a jQuery component from the ASP.NET server side and the answer for simple things like this status bar is that you can simply inject the necessary JavaScript into the page via the ClientScript object (or ScriptManager if you're using MS AJAX). For example assume for a second that you'd like to set the initial status message that is displayed when the page loads from ASP.NET code you can use code like this to drive it:

protected void ShowStatus(string message, int timeout)
{
 
    var script =
@"
jQuery(document).ready( function() {{ 
var status = '{0}';
_statusbar = new StatusBar(null,{{showCloseButton: true,                                          
                            additive:true,                                        
                            afterTimeoutText: status}} );        
_statusbar.show(status,{1});
}});";      
 
    this.ClientScript.RegisterStartupScript(this.GetType(),
                      "showStatus",
                      string.Format(script, message, timeout), true);      
}

Then from anywhere in your page code:

this.ShowStatus("Click to start",0);

And voila you've got server Page interaction. Note that you'd want to remove the startup code from the script page though so that there won't be any jockeying for which message renders first. You'd have to make sure that the server ShowMessage is called at least once to ensure that an initial message is set and the _statusbar object set. If you'd use this functionality a lot you could wrap this up into a server control even and have a couple of properties that control the initial message and other options of the component to be set from the server side which would eliminate any special knowledge of for example having to set the initial display up front when not calling the ShowStatus method explicitly. Probably overkill for this simple component, but useful for more complex components.

As a jQuery Plug-in?

As mentioned this is a first cut of the refactored class and it probably needs a little more work to clean up a few odds ends. I am also trying to think of some ways to make this work more like a jQuery plug-in, but I can't think of a way that this would work effectively.

jQuery allows for utility functions on the jQuery static instance, but I don't think that the Statusbar class really makes a good fit as a static function/object since all it would do is add the $/jQuery prefix to the syntax. There's no benefit there that I can see. It also doesn't work well as a jQuery matched set operation function since the status bar is basically a static object - it's not operating against a matched set but always the same static object. In short, I think making this a jQuery plug-in would only complicate the component.

Anybody have any thoughts on this?

Anyway I hope this is useful to a few of you. I know I've been using statusbars in most of my applications for some time and this component makes the process for application level status displays very easy. I hope this has given you some ideas of how you can create a few helper functions/classes for your client code.

Download: wwjQuery.zip

Posted in HTML  JavaScript  jQuery  

The Voices of Reason


 

Matt Brown
June 13, 2008

# re: A jQuery Client Status Bar

I could see this being very useful in many of my applications. It's subtle enough that it stays out of the way, yet has enough power to guide the user along with whatever they are doing.

Nice job!

Vlad
June 14, 2008

# re: A jQuery Client Status Bar

Thank you very much!
I really like your idea and the way you implemented it.

leilei
June 17, 2008

# re: A jQuery Client Status Bar

I like this article.
and I updated the name of a picture. I'm sorry.

Greg
June 22, 2008

# re: A jQuery Client Status Bar

Definitely like the idea of the functionality it provides, but how do you make the text and close button opaque? They are a bit transparent as well.

Rick Strahl
June 23, 2008

# re: A jQuery Client Status Bar

@Greg - all the display attributes are determined by the CSS classes. Either create new classes and new styles or modify the styles I provided above by removing the opacity in the CSS classes.

Greg
June 23, 2008

# re: A jQuery Client Status Bar

Well, I would still like for the actual statusbar to be a bit transparent, but the items on the status bar should not be, IMO. I tried wrapping the text and closebutton elements in another div and explicitly setting the opacity to 100 with !important on the sub div, but they still maintained their opacity from the parent. Any ideas?

Rick Strahl
June 23, 2008

# re: A jQuery Client Status Bar

As far as I know you can't do that with HTML transparency. Any client content/container will automatically inherit the parents transparency. You *may* be able to do that by overlaying another top level DIV with absolute positioning and keep that non-transparent but that's too much of a hassle for a generic solution.

Mr Red
July 07, 2008

# re: A jQuery Client Status Bar

I will be trying this as I just found IE7 (and other apparently) do not always allow access to the status bar.

Just a thought but I run a script to change the message cyclicly - and thought maybe the opacity might be altered cyclicly - so that it give visiblity of the background. Or am I being too hopeful.

If successful I should credit my source - on the website - but have a gold star for the time being.

thomas
July 17, 2008

# re: A jQuery Client Status Bar

Hi
very well done thie status bar.
However, there is a lil bug in the wwjQuery.js file.
wanting to show the close button, it did'nt showed the following text.
I fixed it by removing the second "</div>" on line 96.
greetins
thomas

NoAJAX4You
November 04, 2008

# re: A jQuery Client Status Bar

so nice to see that M$ itself has adopted Jquery. I just have one thing to say to that

"Die postback, die!" For those doing ASP.NET pages + embedded JavaScript + embedded SQL + viewstate + code behind, I have to say...

"YOU ARE MESSY, MOVE ON!"

1337
July 27, 2009

# re: A jQuery Client Status Bar

im the 1337 person here. when I look at your demo Rick .. its very satisfactory, but I cant get the simple functions to work with your line:
<?php
showStatus("Photo Collection has been updated",5000);
?>
, just to test the function. the css works, they are included correct. please help

I have an index.php where I include *.js and so on in the <head> tag. but I get a fatal error:
Fatal error: Call to undefined function showStatus() in index.php on line 26

can't I use these jquery functions in php? and how? :/

Rick Strahl
July 27, 2009

# re: A jQuery Client Status Bar

This is client side - you can't use this in PHP code, it's client side JavaScript that needs to execute showStatus.

1337
July 27, 2009

# re: A jQuery Client Status Bar

so what you'r saying I can not use your example in PHP.

which language do I need to use then?

Bisweswar Sahu
August 07, 2010

# re: A jQuery Client Status Bar

I had added CSS details including wwjquery.min.js, wwjQuery.js files.
$(document).ready( function() { ... then call showStatus("Photo Collection has been updated",5000);, Neither I am getting error or Status bar as I like.

Can u provide me sample page with necessary files to get the appropiate status bar.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024