Comments
paul.nowak wrote: Matt, thanks for the comments. I made an error on the version of Plone. It's 2.5 Plone running on Zope 2.9x. In regards to the additional products, we have a skin installed and we have a product that we had custom developed for us that connects to a PostgreSQL database. We've looked at slow PostgreSQL queries causing problems and have not been able to find an issue. We've also tested for the case where the PostgreSQL server is down and have not been able to create an issue. We therefor...
Cloud Expo on Google News


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
SYS-CON.TV
Top Links You Must Click On


Java Feature — Jakarta Struts & JavaServer Faces
The add-and-remove pattern

A previous article compared Jakarta Struts and JavaServer Faces implementations of five simple design patterns for list selection. (JDJ, Vol. 11, Issue 3).

Long lists and ordered selections require a more complex design pattern. This pattern displays available items in one list and chosen items in another so the user's choices are always visible and easily modified.

This design pattern is commonly called a Dual List or Dual Listbox selector. It is also known as the Selection Summary or List Builder pattern. In the Java Look and Feel Design Guidelines, it's called the Add-and-Remove pattern:

Typical Struts implementations of this pattern require JSPs, Java, and JavaScript. JavaServer Faces doesn't need JSPs, but they're used here for easy comparison.

Listing 1 shows the JSP for Struts and Listing 2 shows the JSP for JavaServer Faces. Complete code listings for the backing beans, config files, and other code for all six list selection patterns can be downloaded from the JDJ Web site.

Jakarta Struts Implementation
Using Jakarta Struts, the JSP for this pattern defines a table layout with three columns. In the first and third columns, the Available and Chosen lists are implemented using the Struts tags <html:select> and <html:optionsCollection>. For internationalization, the labels can use the <fmt:message> tag from the JavaServer Pages Standard Tag Library. Many people find Struts and JSTL tags a powerful combination.

<table border="0" cellpadding="0" cellspacing="5">
   <tr align="middle" valign="center">
     <td>
       <fmt:message key="titles.available"/><br />
       <html:select property="availableValues"
         multiple="true" size="7"
         style="width:80px;" styleId="available"
         onchange="doUpdate( false, true );">
         <html:optionsCollection
         property="availableList"/>
       </html:select>
     </td>
...
     <td>
       <fmt:message key="titles.chosen"/><br />
       <html:select property="chosenValues"
         multiple="true" size="7"
         style="width:80px;" styleId="chosen"
         onchange="doUpdate( true, false );">
         <html:optionsCollection
         property="chosenList"/>
       </html:select>      </td>
   </tr>
</table>

The form bean contains the "availableList," "availableValues," "chosenList," and "chosenValues" properties used in the JSP.

private List availableList = new ArrayList();
private String[] availableValues = new String[ 0 ];
private List chosenList = new ArrayList();
private String[] chosenValues = new String[ 0 ];
    ...
public List getAvailableList()
public void setAvailableList( List list )
public String[] getAvailableValues()
public void setAvailableValues( String[] list )
public List getChosenList()
public void setChosenList( List list )
public String[] getChosenValues()
public void setChosenValues( String[] list )
    ...

The "availableList" and "chosenList" properties store the lists of available values as LabelValueBeans. The "availableValues" and "chosenValues" properties store the selected values as arrays of Strings.

For the Add-and-Remove pattern, these selected values are of no interest. We don't have to tell the server which values are selected but which items appear in the list contents. However, when forms are submitted, list contents don't get sent back to the server; only their selected values do. This is usually the most efficient way to process forms, but for this design pattern it's a problem. (see Figure 1)

There are several ways to solve this problem. One way is to submit the form every time the list contents change. This produces excess screen refreshes and network traffic. Another way is to use AJAX technology to communicate with the server. This reduces screen refreshes, but still generates network traffic. There's no need to generate network traffic until the user completes their changes.

The best solution is to store the selected values in a hidden control. This way the values get sent back to the server only once, when the form is submitted. It's sufficient to store only the chosen values; changes to both lists can be derived from them. In this example, we'll store the chosen values as a delimited string in a hidden text field.

Using this hidden field, the buttons in the middle column can be implemented as follows:

<td>
   <br />
   <input type="button" style="width:100px;" id="add" onclick="
doMove( 'available', 'chosen', false );" value="<fmt:message key='add'/>" /><br />
   <input type="button" style="width:100px;" id="addAll" onclick=
"doMove( 'available', 'chosen', true );" value="<fmt:message key='addAll'/>" /><br />
   <br />
   <input type="button" style="width:100px;" id="remove" onclick=
"doMove( 'chosen', 'available', false );" value="<fmt:message key='remove'/>" /><br />
   <input type="button" style="width:100px;" id="removeAll" onclick=
"doMove( 'chosen', 'available', true );" value="<fmt:message key='removeAll'/>" />
   <html:hidden styleId="chosenItem" property="chosenItem" />
</td>

The buttons are implemented using standard HTML <input> tags. The <html:hidden> field stores the chosen items as a delimited string. The items are stored by invoking the JavaScript "doMove()" function, which performs all four of the button actions:

/**
* Move selected items between lists.
* <p>
* @param sourceId ID of source list
* @param destId ID of destination list
* @param all true iff moving all
*/
function doMove( sourceId, destId, all )
{
    // Move the items between the lists.
    var sourceElem = document.getElementById( sourceId );
    var destElem = document.getElementById( destId );
    for( var i = 0; ( i < sourceElem.length ); )
    { if( sourceElem.options[ i ].selected || all )
       { var newOption = document.createElement( "OPTION" );
       newOption.text = sourceElem.options[ i ].text;
       newOption.value = sourceElem.options[ i ].value;
       destElem.options[ destElem.length ] = newOption;
       sourceElem.remove( i );
       }
       else
         i++;
    }

    // Update the button states.
    doUpdate( false, false );

    // Store the chosen items in a hidden field.
    var chosenItem = document.getElementById( "chosenItem" );
    var chosenList = document.getElementById( "chosen" );
    chosenItem.value = "";
    for( var i = 0; ( i < chosenList.length ); i++ )
    { chosenItem.value += chosenList.options[ i ].value + '|';
    }
}

Besides implementing the button actions, it eases the users' learning curve to disable these actions when they don't make sense. For example, when there are no selected items, the "Add" and "Remove" buttons can't be used. When the available list or chosen list is empty, the "Add All" or "Remove All" button can't be used.

The "doUpdate()" function enables or disables the buttons based on the user's selections and the list contents. (see Figure 2) The "doUpdate()" function is invoked from the "doMove()" function above as an "onchange" handler for the lists, and as an "onload" handler in the <body> tag to initialize the button states.

/**
* Update the button states based on whether
* lists have contents and selected items.
* Deselect list items if requested to ensure
* at most one list contains selections.
* <p>
* @param offAvailable deselect available list
* @param offChosen deselect chosen list
*/
function doUpdate( offAvailable, offChosen )
{
   // Get the lists and deselect if requested.
   var availableList = document.getElementById( "available" );
   var chosenList = document.getElementById( "chosen" );
   if( offAvailable ) availableList.selectedIndex = -1;
   if( offChosen ) chosenList.selectedIndex = -1;
   // Update the button states.
     document.getElementById( "addAll" ).disabled =
( availableList.length == 0 );
     document.getElementById( "removeAll" ).disabled =
( chosenList.length == 0 );
     document.getElementById( "add" ).disabled =
( availableList.selectedIndex < 0 );
     document.getElementById( "remove" ).disabled =
( chosenList.selectedIndex < 0 );
}

Using these JavaScript functions, list contents are correctly updated and the user's chosen items are stored in the hidden field. When the form is submitted, the user's "chosen" list is read from the hidden field. In this example, it's used to re-populate both lists to reflect the user's choices.

Lists are re-populated by using the "languageList" in the form bean. This is a constant list containing all possible choices. The "move" method of the form bean manipulates the "available" and "chosen" lists based on the contents of the hidden "chosenItem" field.

private List languageList = new ArrayList();
private String chosenItem = "";
    ...
public List getLanguageList()
public void setLanguageList( List list )
public String getChosenItem()
public void setChosenItem( String items )
public void move( List sourceList, String[] sourceValues, List destList )
    ...


About Heman Robinson
Heman Robinson is a senior developer with SAS Institute in Cary, N.C. He holds a BS in mathematics from the University of North Carolina and an MS in computer science from the University of Southern California. He has specialized in GUI design and development for 15 years and has been a Java developer since 1996.

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

Register | Sign-in

Reader Feedback: Page 1 of 1

"Complete code listings for the backing beans, config files, and other code for all six list selection patterns can be downloaded from the JDJ Web site." Where is it?

A previous article compared Jakarta Struts and JavaServer Faces implementations of five simple design patterns for list selection. (JDJ, Vol. 11, Issue 3). Long lists and ordered selections require a more complex design pattern. This pattern displays available items in one list and chosen items in another so the user's choices are always visible and easily modified.

A previous article compared Jakarta Struts and JavaServer Faces implementations of five simple design patterns for list selection. (JDJ, Vol. 11, Issue 3). Long lists and ordered selections require a more complex design pattern. This pattern displays available items in one list and chosen items in another so the user's choices are always visible and easily modified.

A previous article compared Jakarta Struts and JavaServer Faces implementations of five simple design patterns for list selection. (JDJ, Vol. 11, Issue 3). Long lists and ordered selections require a more complex design pattern. This pattern displays available items in one list and chosen items in another so the user's choices are always visible and easily modified.


Your Feedback
Bill Dornbush wrote: "Complete code listings for the backing beans, config files, and other code for all six list selection patterns can be downloaded from the JDJ Web site." Where is it?
n d wrote: A previous article compared Jakarta Struts and JavaServer Faces implementations of five simple design patterns for list selection. (JDJ, Vol. 11, Issue 3). Long lists and ordered selections require a more complex design pattern. This pattern displays available items in one list and chosen items in another so the user's choices are always visible and easily modified.
n d wrote: A previous article compared Jakarta Struts and JavaServer Faces implementations of five simple design patterns for list selection. (JDJ, Vol. 11, Issue 3). Long lists and ordered selections require a more complex design pattern. This pattern displays available items in one list and chosen items in another so the user's choices are always visible and easily modified.
n d wrote: A previous article compared Jakarta Struts and JavaServer Faces implementations of five simple design patterns for list selection. (JDJ, Vol. 11, Issue 3). Long lists and ordered selections require a more complex design pattern. This pattern displays available items in one list and chosen items in another so the user's choices are always visible and easily modified.
Enterprise Open Source Magazine Latest Stories . . .
This is a deal that has been around for all of this year, and I know the NYC-based guy charged with pulling the technical pieces together. He has been looking at software platforms for months and separating contenders from pretenders based on the criteria he's established. To my knowle...
3Leaf Systems, the well-funded start-up, dropped its fig leaf Tuesday and took a running jump into the pools of memory, I/O and cache that it can construct and deconstruct at will based on the application, creating scale-up shared-memory SMP systems the likes of mainframes, proprietary...
Funambol, a provider of open source mobile cloud sync and push email for billions of phones, today announced it has acquired Zapatec, Inc., a leader of AJAX web 2.0 frameworks. The acquisition enables Funambol to uniquely address the industry pervasive device fragmentation challenge th...
Plone and Drupal are two leading open source Content Management Systems (CMS). Both were recognized in the 2009 Open Source CMS awards, run by Packt Publishing. Both also have large installed bases and large developer communities. This is made evident by some quick searching on Googl...
SOASTA, a provider cloud testing, today announced that performance engineers can now build web application tests in Apache JMeter, the most popular open source load testing tool, and run them in SOASTA's Global Test Cloud. Deploying JMeter tests to the Cloud has been a complex, time-co...
Yahoo! Inc. (Nasdaq:YHOO), a leading global Internet company, took its second major step in five months towards open-source cloud computing today, debuting an open source version of Traffic Server, a high performance application server for builders of cloud services. Traffic Server ena...
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