Thursday, October 21, 2010

JSF 2.0 - New features (part 3 of 3)

Note: below description uses Eclipse Indigo, Tomcat 7.0.28 and MyFaces 2.1.7. 

Requirements:
You will learn:
  • support for Ajax
  • support for GET and creating bookmarkable URLs

This is the third post about new features that could be found in JSF 2.0 comparing to JSF 1.x. In the previous post (part 1), I described templating mechanism and simplified navigation model. In the second post (part 2), I described resource loading mechanism. In this post I would like to focus on the built in Ajax support and on possibility to create bookmarkable URLs.

Ajax support.
Ajax is a very wide issue. I would like to show only one of the simplest example - refreshing part of the page after some action. The purpose of this example is to show that using simple Ajax does not require any additional configuration or libraries.
In the sample application I have a page bikesList.xhtml. This page shows the bikes list in selected category (category is chosen in main menu on left). Some of the bikes have discount price. I have two buttons (above the displayed bikes list) acting as bike list filters. Pressing those buttons causes filtering the list and reloading it on the view. For example: if I press a button "Discount bikes" (in red box), only one bike will be shown on a list (Magnum bike with doscount price, marked by red box). If I press "All bikes" - all bikes from the category will be shown:



The idea is to reload the bike list after pressing the button, without reloading the whole page. This is done by Ajax call which is "hooked" to the buttons:
<ui:define name="content">
        <h:commandButton actionListener="#{bikesListBean.showAllBikes}" value="#{msg['bikes.filter.all']}">
            <f:ajax render="bikesTable"  />
          </h:commandButton>
              
          <h:commandButton actionListener="#{bikesListBean.showDiscountBikes}" value="#{msg['bikes.filter.discount']}">
            <f:ajax render="bikesTable"  />
          </h:commandButton>
           
        <h:dataTable id="bikesTable" value="#{bikesListBean.bikesList}" var="b">
...
</ui:define>
Ajax call defined by <f:ajax render="bikesTable" /> causes reloading the corresponding part of thw page with id=bikesTable. In our case this is the list  <h:dataTable id="bikesTable" ... > which shows all or filtered bikes. Simple - isn't it?

Creating bookmarkable URLs (GET support).
Why do I need GET? Consider this situation: I found interesting bike in the Bike Shop. I would like to get the URL and send it to someone in order to show what I found. Quite normal thing isn't it? Unfortunately not possible in JSF 1.x because of lack of GET support. JSF 1.x is POST-centric, so passing parameters in the URL wiht GET was not possible - so I have no way to save the URL.
JSF 2.0 provided GET support by introducing so-called "view parameters". A page which uses a special component for view parameters, is able to catch incoming view parameters (they are in the URL) and update page model (i.e. fields in managed bean) with their values. Moreover standard conversion and validation of the incoming parameters is possible - just like for the POST data.

How it work in real example? Let's go back to our sample application. We have a page named bikesList.xhtml which shows all bikes. We also have a page named bikeDetails.xhtml which shows the detail of selected bike. I would like to see the particular bike and take the URL with it and send it to someone. So the bikeDetails.xhtml page will contain view parameter component:
<f:metadata>
  <f:viewParam name="bikeId" value="#{bikeDetails.bikeId}"/>
  <f:event type="preRenderView" listener="#{bikeDetails.loadBike}"/>
</f:metadata>
Page expects the URL parameter named bikeId, then value of this parameter is copied into the model to the field #{bikeDetails.bikeId}. For now skip <f:event .../> component - I will back to it at the end.
Where those parameters are created and passed to the URL? JSF 2.0 provides two components allowing to add GET parameters to the target URL: <h:button /> and <h:link />(they work similar to the POST-centric <h:commandButton /> and <h:commandLink). In our example bikesList.xhtml page uses <h:button /> for each presented bike to construct the button which navigates us to bikeDetails.xhtml and sets bikeId as a parameter:
<h:dataTable id="bikesTable" value="#{bikesListBean.bikesList}" var="b">
...
<h:button outcome="bikeDetails" value="#{msg['bikes.list.seebike']}">
  <f:param name="bikeId" value="#{b.id}"/>
</h:button>
...
</h:dataTable>
Notice outcome attribute and its value - it points to the target page where view parameters component is used. Simplified navigation is used here. Generated URL looks like this:

http://localhost:8080/JSF2Features/faces/bikeDetails.xhtml?bikeId=5

We have bokkmarkable URL which can be saved and sent to other people and used later.

Solution with view parameters on bikeDetails.xhtml uses another new feature in JSF 2.0: system events. We register a special listener using the tag
<f:event type="preRenderView" listener="#{bikeDetails.loadBike}"/>

The listener is executed before the view is rendered. What is the benefit? When a view is reached, view parameter is copied into the managed bean and listener is executed and after that the whole view (page) is rendered. Our listener uses passed bikeId to load the selected bike from repository like database. When the page is rendered, the proper bike is loaded from repository and ready to be displayed - we do not have to wait for loading the data.

That's all. We are ready to test the application. After deploying application on the server and starting the server, we have to open a browser and type in URL:

http://localhost:8080/JSF2Features



-------------------------------------------
Download source files:

Note: make sure that Java, Eclipse and Tomcat are properly installed and configured for running the project (additional configuration may be required if different directories are used).

Eclipse complete sample project is here (with all required libraries). The sample project is a ready to run application which contains all described JSF 2.0 features in first, second and this (third) post. You can also download a war file located here (just copy it inside webapps folder in Your Tomcat and start Tomcat with the script startup.bat)

3 comments:

Tushar said...

Thanks for the detailed explanation. This is really good for me. I am a novice in JSF.

The source code / war file aren't available. Can you make it available ?

Anonymous said...

I am new to JSF. It gave me a good understanding on Facelets and Ajax support. Thank you very much for providing a real time application.

zanaoi said...

Thanks for the detailed explanation. This is really good for me.