Integrating Ajax into your Facelets pages: Death to JSF's request-response cycle
If you're doing Facelets development, this might be the most important tutorial you will ever read. It will explain to you how to throw out that annoying request-response cycle, and explain how to integrate Ajax based JSF components with a dynamically re-rendering Facelets page snippet.
Facelets is a comprehensive and full featured template engine, and if JavaServer Faces 2.x is your presentation tier technology of choice, using Facelets is pretty much a given. But one of the frustrating problems with Facelets is the fact that each request-response cycle requires a full page refresh, a process that not only makes the application feel slow and less responsive, but it also puts greater load on both the network and server side resources. JSF 2.0 introduced a whole whack of great new tools for incorporating Ajax into your applications, but there is no clear and obvious way to use the Ajax based facilities built into tools like the commandLink and commandButton that allow those components to trigger an Ajax based refresh of a given section of a Facelets template.
An Ajax based request-response cycle using Facelets
Now, you'll notice that I chose my words in that previous paragraph carefully. I said there was no clear and obvious way to integrate JSF based Ajax triggers with a Facelets template, but that doesn't mean it can't be done. In fact, it can be done, and it's really not that complicated.
For the example will will develop in this tutorial, the main content area of our application will update itself through Ajax based calls. As you can see in the following images, the central content, which transitions for asking the name, the date of birth and finally a confirmation page, will all be updated through Ajax calls. Right now we are just concentrating on moving between pages using Facelets, JSF and Ajax, so no actual input is being taken from the user. After all, we want to walk before we can run, and there's no point in complicating things right now by taking user input; clicking on the commandLink will be user input enough.
Working with the FacePainter
The actual content to be displayed here varies, which mean we need a variable to keep track of what should be displayed here. And since variables in Java need to be contained within a class, we will need to create a class, too. The class will be named FacePainter, and the variable will be a String named mainContent. Furthermore, since the landing page of the application is the one that asks the user when their birthday is, we will initialize the mainContent property to content/01name.xhtml.
package com.mcnz.facelets; import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; @ManagedBean(name="facePainter") @SessionScoped public class FacePainter { private String mainContent = "content/01name.xhtml"; public String getMainContent() { return mainContent; } public void setMainContent(String mainContent) { this.mainContent = mainContent; } }
Facelets, JSF ManagedBeans and Ajax
So the content area varies, as is evidenced by the fact that we have created a variable that tracks it. But when does the content variable change? Well, it changes whenever a user clicks the next button and chooses to move to a new page. Some server-side logic is required to make this type of logic happen, so our application now calls for the services of a manged bean. We'll call our managed bean UserInfo and add three methods, one that takes the user to the landing page, one that processes the username and one that processes the birthday information.
package com.mcnz.facelets; import javax.faces.bean.ManagedBean; import javax.faces.bean.ManagedProperty; import javax.faces.bean.SessionScoped; @ManagedBean @SessionScoped public class UserInfo { @ManagedProperty(value="#{facePainter}") public FacePainter facePainter; public FacePainter getFacePainter() { return facePainter; } public void setFacePainter(FacePainter facePainter) { this.facePainter = facePainter; } public void backToLandingPage() { facePainter.setMainContent("content/01name.xhtml"); } public void captureUsername() { facePainter.setMainContent("content/02birthday.xhtml"); } public void captureBirthday() { facePainter.setMainContent("content/03summary.xhtml"); } }
Next, we are going to copy the content of the layout.xhtml page into a new page called index.xhtml, with one small change: rather than hard coding the name of a page to include in the content area, we will simply reference the mainContent variable of the FacePainter:
<div id="content"> <ui:insert name="content"> <ui:include src="#{facePainter.mainContent}" /> </ui:insert> </div>
And that is how to create your managed beans that will be used to dynamically update the mainContent variable of the FacePainter, along with the code snipped used by the Facelets template to dynamically update the content delivered to the client using an Ajax based request from a JSF component. In part two of this tutorial, we will bring all of these components together to complete the Ajax based Facelets application.
JSF, Facelets and Ajax Tutorial: Part II