Tuesday, November 22, 2005

AJAXifying JSF (aka Making AJAX Enabled Components in MyFaces)

There has been a lot of discussion on the MyFaces developers list on how best to incorporate AJAX (Asynchronous JavaScript and XML) into JavaServer Faces (JSF) components. The first components were simple updating components that would retrieve updated information from the server and replace some elements' innerHTML. These included an InputSuggestAjax component that worked like Google Suggest and AutoUpdateDataTable that would get updated list information and update a table in place at a specified interval. Both very cool components made by Martin Marinschek. The main work on these was to encode an ajax response that was just the html required to replace the current html that was being displayed.

I needed components that could be interactive and update the backing model on the server side as well as update so there was a lot of extra work required.

On the client:

  1. Instead of submitting forms in the traditional way, everything has to be submitted through the XMLHttpRequest using javascript.
  2. Components had to be javascript ready to push their changes to the server
  3. Error handling (validation, etc) had to be done dynamically on the client side
On the server:
  1. Decode an incoming request
  2. Update backing model components
  3. Return an error response or a success response
The normal JSF lifecycle consists of the following phases:
  1. Restore view
  2. Apply request values; process events
  3. Process validations; process events
  4. Update model values; process events
  5. Invoke application; process events
  6. Render response
With a normal request you would go through this entire process on every component in the view tree. When you are just updating a single component, this lifecycle is far from optimal. In order to short circuit this lifecycle, a PhaseListener is executed before the Apply Request Values phase, performs the lifecycle on the affected component(s) only, renders a relatively tiny ajax xml response, then completes the response so nothing further is done. So the only phase that is fully executed is the Restore View phase. This should show some major performance improvements.

The Components

All of the components had to be modified to support this new scripting when decoding and when encoding (rendering). The currently available components that you can use and test are:

- inputText (with options to show buttons for submit and cancel, default is to
submit onChange)
- selectManyCheckbox
- selectOneRadio
- selectBooleanCheckbox (with options to use on/off images instead of
a checkbox)

These are available as part of the MyFaces Sandbox package. See inputAjax.jsp for examples on usage. The best thing about these components to a developer is the ease of use, for instance, using inputTextAjax is just as simple as using inputText:

<s:inputtextajax value="#{inputAjaxBean.text2}" id="text2" forceid="true" onsuccess="successful" onfailure="failure" onstart="starting" showokbutton="true" showcanceltext="true"/>

( See wiki documentation for more info on usage. )

I'd love to hear any comments or suggestions you may have.