Wednesday, August 5, 2009

Shopping Cart Web Application - Part 10 - AJAX

Introduction
Asynchronous JavaScript and XML (AJAX) is a group of interrelated web development techniques used for creating interactive web applications or rich Internet applications. With Ajax, web applications can retrieve data from the server asynchronously in the background without interfering with the display and behavior of the existing page. Data is retrieved using the XMLHttpRequest object or through the use of Remote Scripting in browsers that do not support it. Despite the name, the use of JavaScript and XML is not required, and they do not have to be used asynchronously

What you need before we get started

What we will cover
  • Advantages of AJAX
  • RichFaces
  • Limitations and rules
  • Shopping cart

Level
  • Beginner

Advantages of AJAX
  • Nice user experience - AJAX gives the user a way to interact with a website without having to wait for lengthy refreshes on a website. Sections of pages can be reloaded individually without having to reload the whole page
  • Less bandwidth used - instead of the full contents of the HTML page being sent to and from the server only the required information is transmitted. The network utilization is minimized and quicker operations occur
  • Limited processing on the server — Users may perceive the application to be faster or more responsive because only the necessary data is sent to the server, the server is not required to process all form elements. By sending only the necessary data, there is limited processing on the server. There is no need to process all form elements, process the viewstate, send images back to the client, and no need to send a full page back to the client

RichFaces 
RichFaces is an open source framework that adds Ajax capability into existing JSF applications without resorting to JavaScript. RichFaces leverages JavaServer Faces framework including lifecycle, validation, conversion facilities and management of static and dynamic resources. RichFaces UI library contains components for adding rich user interface features to JSF applications. Create a modern rich user interface look-and-feel with skins-based technology. RichFaces UI components come ready to use out-of-the-box, so developers save their time and immediately gain the advantage of the mentioned above features in Web applications creation. As a result, usage experience can be faster and easily obtained.

RichFaces allows to define (by means of JSF tags) different parts of a JSF page you wish to update with an Ajax request and provide a few options to send Ajax requests to the server. JSF page doesn't change from a "regular" JSF page and you don't need to write any JavaScript or XMLHTTPRequest objects by hands, everything is done automatically.

  • Ajax Filter - RichFaces uses a filter for a correction of code received on an Ajax request. In case of a "regular" JSF request a browser makes correction independently. In case of Ajax request in order to prevent layout destruction it's needed to use a filter, because a received code could differ from a code validated by a browser and a browser doesn't make any corrections
  • Ajax Action Components - There are Ajax Action Components: <a4j:commandButton>, <a4j:commandLink>, <a4j:poll>, <a4j:support>, etc. You can use them to send Ajax requests from the client side
  • Ajax Containers - AjaxContainer is an interface that describes an area on your JSF page that should be decoded during an Ajax request. AjaxViewRoot and AjaxRegion are implementations of this interface
  • JavaScript Engine - RichFaces JavaScript Engine runs on the client-side. It knows how to update different areas on your JSF page based on the information from the Ajax response. Do not use this JavaScript code directly, as it is available automatically

Limitations and Rules
  • Any Ajax framework should not append or delete, but only replace elements on the page. For successful updates, an element with the same ID as in the response must exist on the page. If you'd like to append any code to a page, put in a placeholder for it (any empty element). For the same reason, it's recommended to place messages in the "AjaxOutput" component (as no messages is also a message)
  • Don't use <f:verbatim> for self-rendered containers, since this component is transient and not saved in the tree
  • Ajax requests are made by XMLHTTPRequest functions in XML format, but this XML bypasses most validations and the corrections that might be made in a browser. Thus, create only a strict standards-compliant code for HTML and XHTML, without skipping any required elements or attributes. Any necessary XML corrections are automatically made by the XML filter on the server, but lot's of unexpected effects can be produced by an incorrect HTML code
  • The RichFaces ViewHandler puts itself in front of the Facelets ViewHandlers chain
  • RichFaces components uses their own renderers. On the Render Response Phase RichFaces framework makes a traversal of the component tree, calls its own renderer and puts the result into the Faces Response

Shopping Cart Application

1. RichFaces Filter
I added the RichFaces filter to the web deployment descriptor:

<filter>
 <display-name>RichFaces Filter</display-name>
 <filter-name>richfaces</filter-name>
 <filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
 <filter-name>richfaces</filter-name>
 <servlet-name>Faces Servlet</servlet-name>
 <dispatcher>REQUEST</dispatcher>
 <dispatcher>FORWARD</dispatcher>
 <dispatcher>INCLUDE</dispatcher>
</filter-mapping>

2. RichFaces components
I will only be adding AJAX components to the items.jspx page. The other pages can stay as they are as there isn’t a need to add any AJAX components to them. The first thing I did was add the RichFaces tag library xml namespaces to the items.jspx page. Below is the completed items.jspx page. I you compare it to the previous version you would realize that there is very little change, I just replaced most of the standard JSF components with RichFaces components.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" 
    xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:a4j="http://richfaces.org/a4j"
    xmlns:rich="http://richfaces.org/rich"
    version="2.0">
<ui:composition template="/template.jspx">
 <ui:define name="body">
  <h:outputText id="headingOutTxt" value="#{msg.items_txt_heading}"
   styleClass="headingOutputText" />
  <a4j:form id="itemListFrm">
   <rich:dataTable id="itemsTbl" var="items" value="#{pc_Items.items}"
    binding="#{pc_Items.itemsTable}" styleClass="dataTable"
    columnClasses="dataTableCol1" rowClasses="dataTableRow1"
    headerClass="dataTableHeader">
    <rich:column id="nameCol">
     <f:facet name="header">
      <h:outputText id="nameHeaderOutTxt"
       value="#{msg.items_txt_name_col_header}" />
     </f:facet>
     <h:outputText id="nameOutTxt" value="#{items.name}" />
    </rich:column>
    <rich:column id="descriptionCol">
     <f:facet name="header">
      <h:outputText id="descriptionHeaderOutTxt"
       value="#{msg.items_txt_description_col_header}" />
     </f:facet>
     <h:outputText id="descriptionOutTxt" value="#{items.description}" />
    </rich:column>
    <rich:column id="priceCol">
     <f:facet name="header">
      <h:outputText id="priceHeaderOutTxt"
       value="#{msg.items_txt_price_col_header}" />
     </f:facet>
     <h:outputText id="priceOutTxt" value="#{items.price}">
      <f:convertNumber pattern="#{msg.currency_pattern}" />
     </h:outputText>
    </rich:column>
    <rich:column id="addActionCol">
     <a4j:commandLink id="buyLnk" value="#{msg.items_lnk_buy}"
      action="#{pc_Items.addItemToBasket}" reRender="basketTbl" />
    </rich:column>
   </rich:dataTable>
   <p />
   <h:outputText id="basketOutTxt" value="#{msg.items_txt_basket}" />
   <p />
   <rich:dataTable id="basketTbl" var="basketItem" styleClass="dataTable"
    columnClasses="dataTableCol1" rowClasses="dataTableRow1"
    value="#{shoppingViewHelper.basket.basketItems}"
    binding="#{pc_Items.basketTable}">
    <rich:column id="basketItemCol">
     <f:facet name="header">
      <h:outputText id="basketTblHeaderOutTxt"
       value="#{msg.items_txt_basket_item_col_header}" />
     </f:facet>
     <h:outputText id="basketItemOutTxt" value="#{basketItem.item.name}" />
    </rich:column>
    <rich:column id="basketItemQuantityCol">
     <f:facet name="header">
      <h:outputText id="basketTblQuantityOutTxt"
       value="#{msg.items_txt_basket_quantity_col_header}" />
     </f:facet>
     <h:outputText id="basketItemQuantityOutTxt" value="#{basketItem.quantity}" />
    </rich:column>
    <rich:column id="basketItemPriceCol">
     <f:facet name="header">
      <h:outputText id="basketTblPriceOutTxt"
       value="#{msg.items_txt_basket_price_col_header}" />
     </f:facet>
     <h:outputText id="basketItemPriceOutTxt" value="#{basketItem.price}" />
    </rich:column>
    <rich:column id="removeActionCol">
     <a4j:commandLink id="removeLnk" value="#{msg.items_lnk_remove}"
      action="#{pc_Items.removeItemFromBasket}" reRender="basketTbl" />
   </rich:column>
   </rich:dataTable>
   <p />
   <h:commandButton id="checkoutBtn" value="#{msg.btn_checkout}"
    action="#{pc_Items.checkout}" />
   <rich:messages errorClass="errorText" /> 
  </a4j:form>
 </ui:define>
</ui:composition>
</jsp:root>

3. Items backing bean
There are two very small changes we need to make to the Items backing bean (Items.java). Our itemsTbl datatable and our basketTbl datatable are bound to javax.faces.component.html.HtmlDataTable objects within our Items.java backing bean. Because our datatables are no longer standard JSF datatables but RichFaces datatables we need to change this binding from a javax.faces.component.html.HtmlDataTable to a org.richfaces.component.UIDataTable.

The end result:



As you can see it was actually pretty simple to get up and running. Please visit the RichFaces demo site to see the full range of RichFaces components in action. You may have to register on their website to view the demo but it is well worth it. Also please read through the RichFaces developers guide . It is very useful reference manual that contains a comprehensive guide to all of the RichFaces components.

3 comments:

Unknown said...

Hi Ross

Is it necessary to do validation both on POJO's and UI mock-up(e.g Ajax validation)

Unknown said...

It depends what kind of validation you are doing. If it is a simple conversion check than it is easy to do that on the UI - if it is more business logic validation like validating an ID than you will need to build something in yourself

joekic said...

Great tutorial, only one critique, the tutorial's name should probably precede the module's name so instead of shopping-cart-core-spring, it should be shopping-cart-spring-core, helps in sorting the modules in the eclipse :) lol ...