Comments
rock333 wrote: At the IaaS Cloud layer virtualisation is going to be essential to allow the self service attributes, all painful and slow to do with physical hardware. Moving up the stack to PaaS and SaaS the use of virtualisation may, as you say, be less required if you put lots of smarts into your software. A lot of software does not have those smarts and by utalising virtualisation of the layers below can manipulate existing software architectures to have more cloudy attributes through automation (eg run load balancers and deploy more servers automagically). Over time, as new investment in software at...
Cloud Expo on Google News
SYS-CON.TV

2008 West
DIAMOND SPONSOR:
Data Direct
SOA, WOA and Cloud Computing: The New Frontier for Data Services
PLATINUM SPONSORS:
Red Hat
The Opening of Virtualization
GOLD SPONSORS:
Appsense
User Environment Management – The Third Layer of the Desktop
Cordys
Cloud Computing for Business Agility
EMC
CMIS: A Multi-Vendor Proposal for a Service-Based Content Management Interoperability Standard
Freedom OSS
Practical SOA” Max Yankelevich
Intel
Architecting an Enterprise Service Router (ESR) – A Cost-Effective Way to Scale SOA Across the Enterprise
Sensedia
Return on Assests: Bringing Visibility to your SOA Strategy
Symantec
Managing Hybrid Endpoint Environments
VMWare
Game-Changing Technology for Enterprise Clouds and Applications
Click For 2008 West
Event Webcasts

2008 West
PLATINUM SPONSORS:
Appcelerator
Get ‘Rich’ Quick: Rapid Prototyping for RIA with ZERO Server Code
Keynote Systems
Designing for and Managing Performance in the New Frontier of Rich Internet Applications
GOLD SPONSORS:
ICEsoft
How Can AJAX Improve Homeland Security?
Isomorphic
Beyond Widgets: What a RIA Platform Should Offer
Oracle
REAs: Rich Enterprise Applications
Click For 2008 Event Webcasts
Busy Status Indicator with JSF 2
How to use an event to trigger changes that update a status indicator.

I've had a few requests on how to write a busy status indicator - you know, the little spinning ball that's there while an Ajax call is active, and which goes away once the request is complete. So, I spent about two hours today, and did just that - including putting it into a component so it's reusable. As usual, it involved no Java, and only a minimal amount of JavaScript.

First, I needed an animated gif for a spinning image - there were a number at http://mentalized.net/activity-indicators - I just picked one. They're all in the public domain, and there are other sites which offer similar animated gif spinners.

After that, I tried to imagine what it would look like in the using page. Something like this seemed appropriate:

   1 <html xmlns="http://www.w3.org/1999/xhtml"
   2       xmlns:ui="http://java.sun.com/jsf/facelets"
   3       xmlns:h="http://java.sun.com/jsf/html"
   4       xmlns:f="http://java.sun.com/jsf/core"
   5       xmlns:ez="http://java.sun.com/jsf/composite/busystatus">
   6 <h:head>
   7     <title>Busy Busy</title>
   8 </h:head>
   9 <h:body>
  10     <h:form id="busyForm">
  11         <h:inputText id="in" value="#{string.string}">
  12             <f:ajax render="out"/>
  13         </h:inputText><ez:busystatus id="busy" for="busyForm:in" /><br/>
  14         <h:outputText id="out" value="#{string.string}"/><br/>
  15         <h:commandButton type="button" value="Click Me"/>
  16     </h:form>
  17 </h:body>
  18 </html>

On line 13, you see a component, busystatus, with a single attribute, "for", which is pointing at the rendered ID of the component I want to monitor. Otherwise, it's a straightforward JSF Ajax app - Ajaxify the "in" component, write to the the "out" component. I had to use the rendered ID (busyForm:in) rather than the JSF id (in), because there was no easy way to do ID resolution inside the component, but we've had to deal with that often enough at this point that the difference shouldn't be too confusing.

We'll also have make sure that the Ajax request lasts long enough to visibly trigger the indicator - that's as simple as adding a Thread.sleep(2000); to the setString method of the bean referenced by #{string}.

With that out of the way, let's write the component. Here's the composite component implementation section (the interface section just refers to the "for" attribute, so there's nothing to see there):

   1 <h:outputScript name="jsf.js" library="javax.faces" target="head"/>
   2 <h:outputScript name="busystatus/busystatus.js" target="head"/>
   3 <script type="text/javascript">
   4     busystatusdemo.init("#{cc.clientId}", "#{cc.attrs.for}");
   5 </script>
   6 <span id="#{cc.clientId}" style="display:none;">
   7    <h:graphicImage id="busyindicator" height="15" width="15" name="busystatus/spinner3-greenie.gif"/>
   8 </span>

Line 1 loads the jsf.js library, if necessary. We'll need it in the next file for listening to events - note that it'll get loaded anyway, from any f:ajax tag we use, but it's good practice to make sure that it's loaded before we try to reference it. Line 2 will load the JavaScript we've written for this component. We could have just put the script inline in the composite component itself, but then we'd bloat the size of the page unnecessarily if we used this component more than once in the page. What works best for performance is going to vary on case by case basis, but since we're trying to create a generally reusable component, this is probably the best way to do it. Lines 3 thru 5 call the init function for this component, which we'll use to associate the component ID with the for attribute: this is the same trick we use for almost every Ajax component on this blog, so again, this shouldn't be surprising. Lines 6 thru 8 define a span wrapping an image. The span is initially set to be invisible with a style attribute, and we'll make it visible via JavaScript calls once the ajax request is active. The image itself is loading the spinning animated gif as a resource - and it's in the same resource library as the component itself.

So, to recap what's happening in this file: We load the required scripts, run an initialization function, and set up an invisible span holding the image we'll display later. Now, let's examine the last file for this component, the busystatus.js file that holds the functions that'll be doing all the work on the page:

   1 if (!window["busystatusdemo"]) {
   2     var busystatusdemo = {};
   3 }
   4 busystatusdemo.onStatusChange = function onStatusChange(data) {
   5     var status = data.status;
   6     var componentID = busystatusdemo[data.source.id];
   7     if (!componentID) {  // if there's no request to listen for this one component, then leave
   8         return;
   9     }
  10     var element = document.getElementById(componentID);
  11     if (status === "begin") { // turn on busy indicator
  12         element.style.display = "inline";
  13     } else {  // turn off busy indicator, on either "complete" or "success"
  14         element.style.display = "none";
  15     }
  16 };
  17 
  18 jsf.ajax.addOnEvent(busystatusdemo.onStatusChange);
  19 
  20 busystatusdemo.init =  function init(componentID, forValue) {
  21     busystatusdemo[forValue] = componentID;
  22 };

Three sections here: Lines 1 thru 3 set up the namespace. Lines 20 thru 22 are the initialization function that creates a map between the component and the for attribute. Let's go over lines 4 thru 18, though, since that's doing the interesting bit...

On line 18, we're adding an event listener - after this call, whenever an event occurs, the onStatusChange function will be called with a single parameter. When that function is called, on lines 6 thru 10, we retrieve the id of the component that generated the event, and use it to look up the associated "for" value, and exit the function if there's no associated "for" value. Then, lines 11 thru 15, we check whether we're beginning the Ajax call, or ending it. If beginning, we display the gif - if ending, we hide the gif.

So, that's our very simple busy component. But please note that this isn't really done. For instance, by revealing and hiding the gif, we're actually altering the layout of the page - there's traditionally two different ways to deal with this: you can either swap between the animated gif and a blank, transparent gif of the same size, or use CSS to hardcode in the size of a span, which wraps the component that's having it's display set to none. Either would work, and both are really out of scope for this blog - my only goal for this blog was to just show you how to use the event to trigger changes that updated a status indicator.

As usual, you can find the code for this blog in the Project Mojarra codebase, under the jsf-demo/ajax-components directory.

Questions? Please ask in the comments section, and I'll do my best to answer them.

Read the original blog entry...

About Jim Driscoll
Jim Driscoll has worked at Sun Microsystems for 12 years, working on such projects as the first version of Servlets (in the Java Web Server), and the initial implementation of Java 2, Enterprise Edition. He is currently a Senior Engineer working on the implementation of Java Server Faces, helping to integrate technologies such as AJAX and Comet into the new release.

In order to post a comment you need to be registered and logged in.

Register | Sign-in

Reader Feedback: Page 1 of 1

Latest AJAXWorld RIA Stories
Lately there has been a lot of buzz around HTML5 Web Sockets, which defines a full-duplex communication channel that operates through a single socket over the Web. HTML5 Web Sockets is not just another incremental enhancement to conventional HTTP communications; it represents a c...
JackBe enterprise mashup software company, on Thursday announced that its award-winning Presto Enterprise Mashup Platform is now running on Amazon Elastic Compute Cloud. ‘Presto Cloud (Community Edition)’ is immediately available at no cost to all members of JackBe’s Mashup Devel...

 

Abstract

There are many different types of command line options that programs need to recognize. Many languages (e.g.: bash and perl) has built-in processing of command line options; Java does not. The Java Command Line Options (JCLO) package performs this task fo...

"We did not enter the search business. [Google] entered the phone business. Make no mistake they want to kill the iPhone. We won't let them... I want to go back to that other question first and say one more thing. This don't be evil mantra - It's bullshit." - Steve Jobs at an emp...
Did you know that PHP runs on Windows?? Run Drupal, WordPress, SugarCRM, or other PHP-based apps on Windows today with the free Microsoft Web Platform Installer. Microsoft WebsiteSpark is a specially designed program for PHP Web developers and designers to help you explore runnin...
Subscribe to the World's Most Powerful Newsletters
Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021


SYS-CON Featured Whitepapers
ADS BY GOOGLE