Skip to main content

A simple JSF2+AJAX example

Posted by cayhorstmann on January 21, 2009 at 8:39 PM PST

JSF2 will provide a standard mechanism for adding AJAX capabilities to JSF
applications. Jim Driscoll has href="http://weblogs.java.net/blog/driscoll/archive/2008/11/a_simple_ajax_j.html">this
example, but it is a bit odd—the property getter is actually a
mutator. Here is a more run-of-the-mill example. The code is at href="http://kenai.com/projects/corejsf/sources">the Kenai site for the
upcoming Core JSF 3rd edition in the ch01/login-ajax directory. I used
Eclipse with the Glassfish v3 plugin and the most current JSF2 module in
Glassfish (2.0.0 B8).

We want to process a login and show a welcome message upon success, all
without a page flip.

The bean class is straightforward. (For simplicity, the code don't actually
check the login credentials.)

package com.corejsf;

import javax.faces.model.ManagedBean;
import javax.faces.model.SessionScoped;

@ManagedBean(name = "user")
@SessionScoped
public class UserBean {
   private String name = "";
   private String password;

   public String getName() { return name; }
   public void setName(String newValue) { name = newValue; }

   public String getPassword() { return password; }
   public void setPassword(String newValue) { password = newValue; }
  
   public String getGreeting() { return name.length() == 0 ? "" : "Welcome to JSF2 + AJAX, " + name + "!"; }
}

In the JSF page, we need to include the AJAX JavaScript library, with the
following incantation:

  <h:outputScript name="jsf.js" library="javax.faces" target="head" />

(The library name has recently changed. In the Public Review spec, it was
called ajax.js.)

To avoid nested IDs for the components that are updated asynchronously, use
the prependId attribute in the form:

  <h:form prependId="false">

Give IDs to the inputText and outputText
components.

  <h:inputText value="#{user.name}" id="name"/>
  <h:inputSecret value="#{user.password}" id="password"/>
  <h:outputText value="#{user.greeting}" id="out"/>

Then define the login button as follows:

  <h:commandButton value="Login" type="button"
    onclick="jsf.ajax.request(this, event, {execute: 'name password', render: 'out'}); return false;"/>

(The function was called javax.faces.Ajax.ajaxRequest in the PR
spec.)

Note that this is not a submit button. When the button is clicked,
the onclick handler is executed, but the form data is not posted
back. There is no page flip. The jsf.ajax.request method makes an
asynchronous request to the server and receives instructions on which
components to update. (Details below.)

The values of the execute and render keys are
space-separated ID lists. The components on the execute list go
through all parts of the JSF lifecycle except for “Render
Response”. Those on the render list go through “Render
Response”.

The input components must be on the execute list, so that the
bean's setters are invoked. (This is where Jim's example was a bit confusing.
His “Count” button isn't updating the model. It just forces the
property getter to be invoked.)

Now let's spy on what goes on under the hood. Execute the View Source
command of your browser. (If you use Eclipse, it defaults to using an internal
browser without a View Source command. That is not good. Select Window →
Web Browser → Default System Web Browser from the menu and run the app
again.)

Note the element

<script type="text/javascript" src="http://weblogs.java.net/blog/cayhorstmann/archive/ch01-login-ajax/faces/javax.faces.resource/jsf.js?ln=javax.faces">

This is the result of the outputScript tag. You can spy on the
script by pointing your browser to

http://localhost:8080/ch01-login-ajax/faces/javax.faces.resource/jsf.js?ln=javax.faces

It contains a documentation of the request function that is
more up-to-date than the Public Review spec:

In Eclipse or Netbeans, it is easy to run the app server in debug mode and
set a breakpoint in the bean's getters and setters.

That's how I found out what needs to go to the execute list.
(In Jim's example, he added a submit button to that list, but it does actually
no good in this case.)

As David Geary and myself were experimenting with different settings, David
questioned whether there was any AJAX going on at all. To settle the question,
I figured out how to set up the TCP monitor in Eclipse. (In Netbeans, this is
much easier, but David says most people he meets prefer Eclipse :-)) Search for
TCP in the Window→Preferences dialog...

Then point your browser to
http://localhost:10333/ch01-login-ajax (or whichever port you set
up). You'll see the requests and responses.

For example, here is the response when clicking the Login button.

<?xml version="1.0" encoding="utf-8"?>
<partial-response><changes><update id="out">
<![CDATA[<span id="out">Welcome to JSF2 + AJAX, Cay!</span>]]></update>
<update id="javax.faces.ViewState"><![CDATA[j_id5:j_id6]]>`````</update></changes></partial-response>

As you can see, the response contains instructions how to update the output
field.

Note that the output field must be present in the page. I tried to avoid the
greeting property by using the rendered attribute:

  <h:outputText id="out" rendered="#{user.name != ''}"  
    value="Welcome to JavaServer Faces, #{user.name}!"/>

That did not work—the AJAX update was not able to add the component
since it didn't exist on the client. (Use View Source to verify that...)

For a chuckle, try a user name of ]]>. With today's version
(2.0.0 B8), it doesn't work. Of course, that's a bug—someone was
insufficiently paranoid
about CDATA
.

What can one learn from all this?

  • View Source is your friend
  • The debugger is your friend
  • The TCP monitor is your friend

With JSF development, you need all the friends you can get :-)

Related Topics >>

Comments

THANKS!

All I have to say is THANK YOU for creating these blog posts on JSF. This one helped me out a lot for something that I'm working on. You've posted several others that I've found very helpful also. For example the one about avoiding the JSF API. I was able to clean up a lot of my old JSF 1.1/1.2 code using those tips. Thanks again, and keep up the good work. Also, I'm looking forward to the new addition of your JSF book. I thought it was supposed to be out by now, but, I still don't see it at Amazon.

Hi Cay - Thanks for the filed bug on CDATA escaping - that's now fixed (with associated unit tests) in the sourcebase, and the nightly should fix the problem. The next release (post-PR) will fix that bug. As for my (admittedly) odd choice of mixing mutators and accessors, I guess I'm just not as concerned by that as you are - it's not that uncommon for the act of observing data to change it - was it really that confusing, or was it merely annoying? I ask, since if it was confusing (or even non-obvious) to *you*, then I obviously need to change it, since you're pretty knowlegable, and if I can't explain it to you, I don't have a chance with a true beginner. (Also, I used that pattern simply because it was how I had written a Comet example last year, and reused some of that code. I could have just done an accessor to a timestamp function, it would have done the same thing - but it's handier to count the accesses for testing, and I used that demo to model some unit tests I wrote..) Also, when I'm coding up a new demo and need to debug it, I never use TCP monitoring - I usually just use Firebug in Firefox to set a breakpoint in the jsf.ajax.response funciton, and look at the contentText property of the xml returned - that'll give you most of what you're looking for. Of course, I also often end up with a breakpoint in the JSF code itself when debugging things like the CDATA bug you reported, but I don't think that's necessary for most folks writing code, unless I've left a bug in there. Jim Driscoll

Best selling Author on Servlets and JSP Marty Hall to Keynote

Hey Guys, Author of More Servlets and JSP, Marty Hall is coming to Bangalore this April to speak on Choosing an Ajax/JavaScript Toolkit: A Comparison of the Most Popular JavaScript Libraries, Pure Java Ajax: An Overview of GWT 2.0, Integrated Ajax Support in JSF 2.0 and Ajax Support in the Prototype JavaScript Library. You can get more information on www.developersummit.com