Skip to main content

TOTD #45: Ajaxifying Java Server Faces using JSF Extensions

Posted by arungupta on September 17, 2008 at 5:47 AM PDT



href="http://blogs.sun.com/arungupta/entry/totd_42_hello_javaserver_faces">TOTD
#42 explained how to create a simple Java Server Faces
application using NetBeans 6.1 and deploy on GlassFish. In the process
it explained some basic
JSF concepts as well. If you remember, it built an application that
allows you to create a database of cities/country of your choice. In
that application, any city/country combination can be entered twice and
no errors are reported.



This blog entry extends href="http://blogs.sun.com/arungupta/entry/totd_42_hello_javaserver_faces">TOTD
#42 and show the list of cities, that have already been
entered,
starting with the letters entered in the text box. And instead of
refreshing the entire page, it uses href="https://jsf-extensions.dev.java.net/">JSF Extensions
to make an Ajax call to the endpoint and show the list of cities based
upon the text entered. This behavior is similar to href="http://en.wikipedia.org/wiki/Autocomplete">Autocomplete
and shows the suggestions in a separate text box.



Let's get started!

  1. Download latest href="https://jsf-extensions.dev.java.net/servlets/ProjectDocumentList?folderID=5580&expandFolder=5580&folderID=0">JSF-Extensions
    release.
  2. Unzip the bundle as:


    style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
    cellpadding="2" cellspacing="2">
    ~/tools >gunzip
    -c ~/Downloads/jsf-extensions-0.1.tar.gz | tar xvf -
  3. In NetBeans IDE, add the following jars to Project/Libraries



    src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-libraries.png">
  4. Edit "welcomeJSF.jsp"
    1. Add the following to the required tag libraries


      style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
      cellpadding="2" cellspacing="2">
      <%@taglib prefix="jsfExt"
      uri="http://java.sun.com/jsf/extensions/dynafaces" %> style="font-weight: bold;">



      The updated page looks like:



      src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-taglib.png">

    2. Add the following tag as the first tag inside
      <f:view>


      style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
      cellpadding="2" cellspacing="2">
      <jsfExt:scripts /> style="font-weight: bold;">



      The updated page looks like:



      src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-jsfext-scripts.png">

    3. Add prependId="false" to "<h:form>" tag.
      The updated tag looks like:



      src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-prepend-id.png">
    4. Add the following fragment as an attribute to
      <h:inputText> tag with "cityName" id:


      style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
      cellpadding="2" cellspacing="2">
      onkeyup="DynaFaces.fireAjaxTransaction(this, {
      execute: 'cityName', render: 'city_choices', immediate: true});" style="font-weight: bold;">



      This is the magic fragment that issues an Ajax call to the endpoint. It
      ensures execute
      portion of the request lifecycle is executed for "cityName" and
      "city_choices" (defined later) is rendered.



      The updated page looks like:



      src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-onkeyup.png">

    5. Add a new <h:outputText> tag after
      <h:commandButton> tag (to hold the suggestions output):


      style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
      cellpadding="2" cellspacing="2">
      <h:outputText id="city_choices"
      value="#{dbUtil.cityChoices}"></h:outputText> style="font-weight: bold;">



      The updated page looks like:



      src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-city_choices_output_text.png">

  5. Add the following fragment to web.xml


    style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
    cellpadding="2" cellspacing="2">
         
     <init-param>

             
    <param-name>javax.faces.LIFECYCLE_ID</param-name>

             
    <param-value>com.sun.faces.lifecycle.PARTIAL</param-value>

           
    </init-param>



    The updated file looks like:



    src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-webxml.png">

  6. Edit "server.Cities" class
    1. Add a new NamedQuery in Cities class (at the mark after
      yellow-highlighted parentheses):



      src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-findall.png">





      The query is:


      style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
      cellpadding="2" cellspacing="2">
      @NamedQuery(name = "Cities.findSimilarName",
      query = "SELECT c FROM Cities c WHERE LOWER(c.cityName) LIKE
      :searchString"),



      This NamedQuery queries the database and return a list of city names
      that matches the pattern specified in "searchString" parameter.

    2. Change the toString() method implementation to return
      "cityName". The updated method looks like:



      src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-tostring.png">



      This allows the city name to be printed clearly.
  7. Add a new method in "server.DatabaseUtil" as:


    style="text-align: left; background-color: rgb(204, 204, 255); width: 100%;"
    cellpadding="2" cellspacing="2">
        public
    Collection<Cities> getCityChoices() {

           
    Collection<Cities> allCities = new
    ArrayList<Cities>();



           
    if (cities.getCityName() != null &&
    !cities.getCityName().equals("")) {

               
    List list = entityManager.createNamedQuery("Cities.findSimilarName").

                       
    setParameter("searchString", cities.getCityName().toLowerCase() + "%").

                       
    getResultList();

               
    for (int i = 0; i < list.size(); i++) {

                   
    allCities.add((Cities) list.get(i));

               
    }

               


            }

           
    return allCities;

        }



    This method uses previously defined NamedQuery and adds a parameter for
    pattern matching.

Now, play time!



The list of created cities is:



alt=""
src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-list.png">



If "S" is entered in the text box (http://localhost:8080/Cities/), then
the following output is shown:



alt=""
src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-s.png">



Entering "San", shows:



alt=""
src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-san.png">



Entering "Sant" shows:



alt=""
src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-sant.png">



Entering "De" updates the page as:



alt=""
src="http://blogs.sun.com/arungupta/resource/images/jsfex-nb61-cities-de.png">



And finally entering "Ber" shows the output as:



alt=""
src="http://blogs.sun.com/arungupta/resource/images/jsfext-nb61-cities-ber.png">



So you built a simple Ajaxified Java Server Faces application using JSF
Extensions.



Here are some more references to look at:

  1. href="https://jsf-extensions.dev.java.net/nonav/mvn/gettingstarted-ajax.html">JSF
    Extensions Getting Started Guide
  2. href="http://java.sun.com/developer/technicalArticles/J2EE/ajax_jsf/">Tech
    Tip: Adding Ajax to Java Server
    Faces Technology with Dynamic Faces
  3. href="https://jsf-extensions.dev.java.net/nonav/mvn/reference-ajax.html">JSF
    Extensions Ajax Reference

Java Server Faces 2.0 has Ajax functionality integrated into the spec
and this should be more seamless. I'll try that next!



Please leave suggestions on other TOTD (Tip Of The Day) that
you'd like to see.
A complete archive of all tips is available href="http://blogs.sun.com/arungupta/tags/totd">here.




Technorati: totd
mysql href="http://technorati.com/tag/javaserverfaces">javaserverfaces
netbeans
glassfish ajax

Related Topics >>

Comments

miojo, DynaFaces offers a way to add very customizable Ajax support to components that don't support it natively. Furthermore, some of us aren't fans of writing GUIs in lots of Java. Different strokes. dxxvi, RichFaces and ICEfaces are both excellent component sets, but they're not always an option. DynaFaces is just one of many solutions to Ajax in JSF. Luckily, we can choose the one that fits our project best.

jsf-extensions, richfaces and icefaces are all great frameworks. As you know, the Ajax storm took everyone by surprise, and folks were rushing to get their frameworks out the door and exposed to the community. One could also say, what is the point of richfaces when you have icefaces.... or vica versa... At any rate, the JSF 2.0 EG is developing a standard client/server side (JSF Ajax) API with help from key members from jsf-extensions, ICESoft ICEfaces, Oracle ADF Faces, JBoss RichFaces to help promote component compatibility.

What's the point of jsf extension when you have richfaces and icefaces? Maybe you'll spend more time learning these faces but it's worth it.

<input type="text" wicket:id="cityName"/>

Sorry, this is how the HTML will look like: <%input type="text" wicket:id="cityName"/> PS: no changes needed for an ajax input text field

This looks so complicated... Wouldn't be easier to just use Java? Non-Ajax: ------------- TextField cityField = new TextField("cityName"); Ajax version: ------------------ AjaxAutocompleteTextField cityField = new AjaxAutocompleteTextField("cityName"); HTML (no changes needed) @see http://wicket.apache.org