Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 1

Exclusive offer: get 50% off this eBook here
JBoss RichFaces 3.3

JBoss RichFaces 3.3 — Save 50%

Enhance your JSF web applications using powerful AJAX components

$23.99    $12.00
by Demetrio Filocamo | October 2009 | Java Open Source Web Development

In this article written by Demetrio Filocamo, we are going to develop the contacts management feature of our application i.e the contact managers, which includes listing, adding, editing, and deleting contacts—all of this the Ajax way!

Moreover, we are going to learn new concepts about the RichFaces component framework and Ajax support.

The main layout

Let's start preparing the space for the core features of the application. We want a three-column layout for groups, contacts list, and contact detail. Let's open the home.xhtml file and add a three-column panel grid inside the body:

<h:panelGrid columns="3" 
width="100%"
columnClasses="main-group-column, main-contacts-list-column,
 main-contact-detail-column">
</h:panelGrid>

We are using three new CSS classes (one for every column). Let's open the /view/stylesheet/theme.css file and add the following code:

.main-group-column {
width: 20%;
vertical-align: top;
}

.main-contacts-list-column {
width: 40%;
vertical-align: top;
}

.main-contact-detail-column {
width: 40%;
vertical-align: top;
}

The main columns are ready; now we want to split the content of every column in a separate file (so we don't have a large and difficult file to read) by using the Facelets templating capabilities—let's create a new folder inside the/view folder called main, and let's create the following empty files inside it:

  • contactsGroups.xhtml
  • contactsList.xhtml
  • contactEdit.xhtml
  • contactView.xhtml

Now let's open them and put the standard code for an empty (included) file:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
xmlns:a="http://richfaces.org/a4j">

<!-- my code here -->

</ui:composition>

Now, we have all of the pieces ready to be included into the home.xhtml file, let's open it and start adding the first column inside h:panelGrid:

<a:outputPanel id="contactsGroups">
<ui:include src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="main/contactsGroups.xhtml"/>
</a:outputPanel>

As you can see, we surrounded the include with an a:outputPanel that will be used as a placeholder for the re-rendering purpose.

Include a Facelets tag (ui:include) into the a:outputPanel that we used in order to include the page at that point.

Ajax placeholders

A very important concept to keep in mind while developing is that the Ajax framework can't add or delete, but can only replace existing elements in the page.For this reason, if you want to append some code, you need to use a placeholder.

RichFaces has a component that can be used as a placeholder—a4j:outputPanel.

Inside a4j:outputPanel, you can put other components that use the "rendered" attribute in order to decide if they are visible or not. When you want to re-render all the included components, just re-render the outputPanel, and all will work without any problem.

Here is a non-working code snippet:

<h:form>
<h:inputText value="#{aBean.myText}">
<a4j:support event="onkeyup" reRender="out1" />
</h:inputText>
</h:form>

<h:outputText
id="out1"
value="#{aBean.myText}"
rendered="#{not empty aBean.myText}"/>

This code seems the same as that of the a4j:support example, but it won't work.

The problem is that we added the rendered attribute to outputText, so initially, out1 will not be rendered (because the text property is initially empty and rendered will be equal to false). After the Ajax response, the JavaScript Engine will not find the out1 element (it is not in the page because of rendered="false"), and it will not be able to update it (remember that you can't add or delete elements, only replace them).

It is very simple to make the code work:

<h:form>
<h:inputText value="#{aBean.myText}">
<a4j:support event="onkeyup" reRender="out2" />
</h:inputText>
</h:form>
<a4j:outputPanel id="out2">
<h:outputText
id="out1"
rendered="#{not empty aBean.myText}"
value="#{aBean.myText}" />
</a4j:outputPanel>

As you can see, you just have to put the out1 component inside a4j:outputPanel (called out2) and tell a4j:support to re-render out2 instead of out1.

Initially, out2 will be rendered but empty (because out1 will not be rendered). After the Ajax response, the empty out2 will be replaced with markup elements that also contain the out1 component (that is now visible, because the myText property is not empty after the Ajax update and the rendered property is true).

A very important concept to keep in mind while developing is that the Ajax framework can't add or delete, but can only replace existing elements of the page. For this reason, if you want to append some code, you need to use a placeholder.

The groups box

This box will contain all the contacts groups, so the user will be able to organize contacts in different groups in a better way.

We will not implement the group box features in this article. Therefore, by now the group column is just a rich:panel with a link to refresh the contact list.

Let's open the contactsGroups.xhtml file and insert the following code:

<h:form>
<rich:panel>
<f:facet name="header">
<h:outputText value="#{messages['groups']}" />
</f:facet>
<h:panelGrid columns="1">
<a:commandLink value="#{messages['allContacts']}"
ajaxSingle="true"
reRender="contactsList">
<f:setPropertyActionListener value="#{null}"
target="#{homeContactsListHelper.contactsList}" />
</a:commandLink>
</h:panelGrid>
</rich:panel>
</h:form>

As you can see, we've put a three-column h:panelGrid (to be used in the future) and a:commandLink, which just sets the contactsList property of the homeContactListHelper bean (that we will see in the next section) to null, in order to make the list be read again. At the end of the Ajax interaction, it will re-render the contactsList column in order to show the new data.

Also, notice that we are still supporting i18n for every text using the messages property; the task to fill the messages_XX.properties file is left as an exercise for the user.

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 1

The contacts list

The second column inside h:panelGrid of home.xhtml looks like:

<a:outputPanel id="contactsList">
<ui:include src='//dgdsbygo8mp3h.cloudfront.net/sites/default/files/blank.gif' data-original="main/contactsList.xhtml"/>
</a:outputPanel>

As for groups, we used a placeholder surrounding the ui:include tag.

Now let's focus on creating the data table—open the /view/main/contactsList.xhtml file and add the first snippet of code for dataTable:

<h:form>
<rich:dataTable id="contactsTable"
reRender="contactsTableDS"
rows="20"
value="#{homeContactsListHelper.contactsList}"
var="contact">
<rich:column width="45%">
<h:outputText value="#{contact.name}"/>
</rich:column>
<rich:column width="45%">
<h:outputText value="#{contact.surname}"/>
</rich:column>
<f:facet name="footer">
<rich:datascroller id="contactsTableDS"
for="contactsTable"
renderIfSinglePage="false"/>
</f:facet>
</rich:dataTable>
<h:outputText value="#{messages['noContactsInList']}"
rendered="#{homeContactsListHelper.contactsList.size()==0}"/>
</h:form>

We just added the rich:dataTable component with some columns and an Ajax data scroller at the end.

Differences between h:dataTable and rich:dataTable

RichFaces provides its own version of h:dataTable, which contains more features and is better integrated with the RichFaces framework.

The first important additional feature, in fact, is the skinnability support following the RichFaces standards.

Other features are row and column spans support (we will discuss it in the Columns and column groups section), out-of-the-box filter and sorting (discussed in the Filtering and sorting section), more JavaScript event handlers (such as onRowClick, onRowContextMenu, onRowDblClick, and so on) and the reRender attribute.

Like other data iteration components of the RichFaces framework, it also supports the partial-row update.

Data pagination

Implementing Ajax data pagination using RichFaces is really simple—just decide how many rows must be shown in every page by setting the rows attribute of dataTable (in our case, we've chosen 20 rows per page), and then "attach" the rich:datascroller component to it by filling the for attribute with the dataTable id:

<rich:datascroller id="contactsTableDS" 
for="contactsTable"
renderIfSinglePage="false"/>

Here you can see another very useful attribute (renderIfSinglePage) that makes the component hidden when there is just a single page in the list (it means the list contains a number of items that is less than or equal to the value of the rows attribute).

A thing to keep in mind is that the rich:datascroller component must stay inside a form component (h:form or a:form) in order to work.

Customizing rich:datascroller is possible not only by using CSS classes (as usual), but also by personalizing our own parts using the following facets:

  • pages
  • controlsSeparator
  • first, first_disabled
  • last, last_disabled
  • next, next_disabled
  • previous, previous_disabled
  • fastforward, fastforward_disabled
  • fastrewind, fastrewinf_disabled

Here is an example with some customized facets (using strings):

<rich:datascroller id="contactsTableDS" for="contactsTable" 
renderIfSinglePage="false">
<f:facet name="first">
<h:outputText value="First" />
</f:facet>
<f:facet name="last">
<h:outputText value="Last" />
</f:facet>
</rich:datascroller>

Here is the result:

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 1

You can use an image (or another component) instead of text, in order to create your own customized scroller.

Another interesting example is:

<rich:datascroller id="contactsTableDS" for="contactsTable" 
renderIfSinglePage="false">
<f:facet name="first">
<h:outputText value="First"/>
</f:facet>
<f:facet name="last">
<h:outputText value="Last"/>
</f:facet>
<f:attribute name="pageIndexVar"
value="pageIndexVar"/>
<f:attribute name="pagesVar" value="pagesVar"/>
<f:facet name="pages">
<h:panelGroup>
<h:outputText value="Page #{pageIndexVar} / #{pagesVar}"/>
</h:panelGroup>
</f:facet>
</rich:datascroller>

The result is:

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 1

By setting the pageIndexVar and pagesVar attributes, we are able to use them in an outputText component, as we've done in the example.

A useful attribute of the component is maxPages that sets the maximum number of page links (the numbers in the middle), which the scroller shows—therefore, we can control the size of it.

The page attribute could be bound to a property of a bean, in order to switch to a page giving the number—a simple use-case could be using an inputText and a commandButton, in order to let the client insert the page number that he/she wants to go to.

Here is the code that shows how to implement it:

<rich:datascroller 
for="contactsList" maxPages="20" fastControls="hide"
page="#{customDataScrollerExampleHelper.scrollerPage}"
pagesVar="pages" id="ds">
<f:facet name="first">
<h:outputText value="First" />
</f:facet>
<f:facet name="first_disabled">
<h:outputText value="First" />
</f:facet>
<f:facet name="last">
<h:outputText value="Last" />
</f:facet>
<f:facet name="last_disabled">
<h:outputText value="Last" />
</f:facet>
<f:facet name="previous">
<h:outputText value="Previous" />
</f:facet>
<f:facet name="previous_disabled">
<h:outputText value="Previous" />
</f:facet>
<f:facet name="next">
<h:outputText value="Next" />
</f:facet>
<f:facet name="next_disabled">
<h:outputText value="Next" />
</f:facet>
<f:facet name="pages">
<h:panelGroup>
<h:outputText value="Page "/>
<h:inputText
value="#{customDataScrollerExampleHelper.
scrollerPage}"
size="4">
<f:validateLongRange minimum="0" />
<a:support event="onkeyup" timeout="500"
oncomplete="#{rich:component('ds')}.
switchToPage(this.value)" />
</h:inputText>
<h:outputText value=" of #{pages}"/>
</h:panelGroup>
</f:facet>
</rich:datascroller>

As you can see, besides customizing the text of the First, Last, Previous, and Next sections, we defined a pages facet by inserting h:inputText connected with an integer value inside a backing bean. We also added the a:support tag, in order to trim the page change after the keyup event is completed. We've also set the timeout attribute, in order to call the server every 500 ms and not every time the user types.

You can see a screenshot of the feature here:

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 1

JBoss RichFaces 3.3 Enhance your JSF web applications using powerful AJAX components
Published: October 2009
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

Adding the column headers

Now we would like to add a header for every column of the dataTable; the simplest way is to just put a facet inside the rich:column component, this way:

<rich:column>
<f:facet name="header">
<h:outputText value="my header" />
</f:facet>
...
</rich:column>

This method also works for the standard h:dataTable component—RichFaces enhances the table heading capabilities by allowing grouping, using the rich:columnGroup component.

Therefore, coming back to our application, we can put the following code inside the rich:dataTable tag in order to define the header of the dataTable:

<rich:dataTable ... >
<f:facet name="header">
<rich:columnGroup>
<rich:column colspan="2">
<h:outputText value="Contacts"/>
</rich:column>
<rich:column breakBefore="true">
<h:outputText value="Name"/>
</rich:column>
<rich:column>
<h:outputText value="Surname"/>
</rich:column>
</rich:columnGroup>
</f:facet>
...

And the result will be as follows:

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 1

Columns and column groups

Using the RichFaces version is also very convenient for extending the dataTable behavior on row rendering.

Let's take a simplified version (without header, footer, and datascroller) of the contactsList table:

<rich:dataTable id="contactsTable"
value="#{homeContactsListHelper.contactsList}"
var="contact">
<rich:column>
<h:outputText value="#{contact.name}"/>
</rich:column>
<rich:column>
<h:outputText value="#{contact.surname}"/>
</rich:column>
<rich:column>
<a:commandButton image="/img/view.png" />
</rich:column>
</rich:dataTable>

It is a normal dataTable and looks like:

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 1

Now let's do a little editing by adding the two attributes— span and breakBefore:

<rich:dataTable id="contactsTable"
value="#{homeContactsListHelper.contactsList}"
var="contact">
<rich:column colspan="2">
<h:outputText value="#{contact.name}"/>
</rich:column>
<rich:column breakBefore="true">
<h:outputText value="#{contact.surname}"/>
</rich:column>
<rich:column>
<a:commandButton image="/img/view.png" />
</rich:column>
</rich:dataTable>

With the above attributes, it looks like:

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 1

What has happened?

We've told to the first column to "span" (you might know the meaning because it's a standard html table column attribute) two columns and the second one to "break before" rendering it, in the sense of closing the row (putting the HTML <  /tr >   tag).

So, the first column fills the space of two columns and the second one is rendered in another row; simple, isn't it?

You can also use the rowSpan attribute in order to span rows instead of columns, as for standard HTML tables.

We can have the same result using a rich:columnGroup component instead of the breakBefore attribute, as in the following example:

<rich:dataTable id="contactsTable"
value="#{homeContactsListHelper.contactsList}"
var="contact">
<rich:column colspan="2">
<h:outputText value="#{contact.name}"/>
</rich:column>
<rich:columnGroup>
<rich:column>
<h:outputText value="#{contact.surname}"/>
</rich:column>
<rich:column>
<a:commandButton image="/img/view.png"/>
</rich:column>
</rich:columnGroup>
</rich:dataTable>

As we can see, the result is exactly the same.

Another use of rich:column and rich:columnGroup is to define a complex table header as we have done in our application, as shown in the previous section.

rich:column contains very useful attributes other than span, breakBefore, and the filtering and sorting attributes (that we are going to see in the next section), which we don't find in the standard h:column component.

For example, in our application, we used the width attribute in order to set the width for every column without using a CSS class just for that.

Out-of-the-box filtering and sorting

Another important feature is the out-of-the-box filtering and sorting support that the rich:dataTable component offers.

<rich:column width="45%" 
sortBy="#{contact.name}"
filterBy="#{contact.name}">
<h:outputText value="#{contact.name}"/>
</rich:column>
<rich:column width="45%"
sortBy="#{contact.surname}"
filterBy="#{contact.surname}">
<h:outputText value="#{contact.surname}"/>
</rich:column>

In order to add this feature to our table, let's just edit the rich:column tags for name and surname, as shown in the following code:

<rich:toolBar>
<rich:toolBarGroup>
<!-- my action buttons here -->
</rich:toolBarGroup>
</rich:toolBar>

You will have a working sort and filter feature for your table just by adding these two attributes!

Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 1

The bottom toolbar

We need a toolbar at the bottom of the table that will contain action buttons for different kinds of action (we will add the button to add a new contact in the next section).

The backing bean

We've seen the connection of the table with a backing bean called homeContactsListHelper—let's create it!

Let's create a new package called main inside book.richfaces.advcm.modules, and create a new class called HomeContactsListHelper inside it.

The Seam component is very simple, as it has just to retrieve the contacts list from the database (groups are not managed by now)—it might look like the following:

@Name("homeContactsListHelper")
@Scope(ScopeType.CONVERSATION)
public class HomeContactsListHelper {
@In(create=true)
EntityManager entityManager;

@In(required = true)
Contact loggedUser;

private List<Contact> contactsList;

public List<Contact> getContactsList() {
if (contactsList ==null) {
// Creating the query
String query="from Contact c where c.contact.id=:fatherId";
// Getting the contacts list
contactsList = (List<Contact>)
entityManager.createQuery(query)
.setParameter("fatherId",
loggedUser.getId())
.getResultList();
}
return contactsList;
}

public void setContactsList(List<Contact> contactsList) {
this.contactsList = contactsList;
}

To summarize—the @Name annotation defines the name of the Seam component/JSF backing bean, @Scope defines the scope of the component, we inject (using the @In annotation) the entityManager component (to query the database using JPA) and the contact instance referring to the logged user, who we outjected during the login phase.

In addition, the bean has a property called contactsList that is lazy initialized into the getContactsList() method by querying the database.

As we are using the conversation scope, we would like to start the conversation when entering the home page. There are different ways to do this—in our case, let's open the /view/home.page.xml file and add the following content:

<begin-conversation join="true" />

So, now when the user navigates to the home page, a new conversation is created if there is none. If not, the existing one would be kept (join="true").

>> Continue Reading Build an Advanced Contact Manager using JBoss RichFaces 3.3: Part 2

[ 1 | 2 | 3 ]]
JBoss RichFaces 3.3 Enhance your JSF web applications using powerful AJAX components
Published: October 2009
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

About the Author :


Demetrio Filocamo

Demetrio Filocamo is a computer science engineer with more then 10 years of experience on both Desktop and Web applications development. He works as a freelance in London and collaborates with some companies and universities in Italy. Demetrio has been developing Enterprise Java Applications using open source solutions for the last five years.

Books From Packt

JBoss AS 5 Development
JBoss AS 5 Development

jQuery 1.3 with PHP
jQuery 1.3 with PHP

Joomla! with Flash
Joomla! with Flash

Drools JBoss Rules 5.0 Developer's Guide
Drools JBoss Rules 5.0 Developer's Guide

JBoss Tools 3 Developers Guide
JBoss Tools 3 Developers Guide

Tomcat 6 Developer's Guide
Tomcat 6 Developer's Guide

Apache MyFaces Trinidad 1.2: A Practical Guide
Apache MyFaces Trinidad 1.2: A Practical Guide

jQuery UI 1.6: The User Interface Library for jQuery
jQuery UI 1.6: The User Interface Library for jQuery

 

 

 

No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
L
1
H
S
P
5
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software