J4Fry AJAX JSF Solution

Characteristics

Attribute Value
Project name J4Fry Ajax JSF Solution [Subproject of J4Fry JSFComponents]
Prerequisites JDK >= 1.4, MyFaces, JSON, EzMorph
CVS module JSFComponents
Responsible developer Alexander Bell

J4Fry AJAX for JSF aims

We provide a AJAX JSF solution, that combines ease of use, stability and performance. Our AJAX solution supports lots of environments: It works inside JSF datatables, together with JSF 1.1 as well as 1.2, with Facelets and even with JSR168 Portlets! We provide true PPR (partial page rendering) and PPS (partial page submit) which means that the rendering process is only executed for the components that are being rerendered and only the fields needed for the request are submitted and processed.

J4Fry AJAX for JSF usage

Refer to the general JSF Components installation for installation instructions.
Nest the AJAX tag inside inputs, buttons or any other JSF tags like this:

<h:inputText value="#{myBean.text}" id="text">
   <fry:ajax event="onchange"
     reRender="idsOfRerenderedTags" action="#{myBean.action}" />

</h:inputText>

If you change the text in this input-field the action "myBean.action" is invoked.
Afterwards the components named in the "reRender" attribute are rerendered.

This tag should NOT be used in conjunction with the h:commandLink tag. HTML links (a tags) aren't made to submit forms, so JSF implementors must so some Javascript tweaking to make h:cammnad links submit forms. This Javascript inferes with the AJAX Javascript in several JSF implementations. Here's a simple workaround:

<h:outputText value="link text" style="cursor:pointer"
  onmouseover="this.style.textDecoration='underline';"
  onmouseout="this.style.textDecoration='none';" >
  <fry:ajax event="onclick" reRender="idsOfRerenderedTags"
    action="#{myBean.action}" />
</h:outputText>

To prevent overlapping requests you can disable some components during the AJAX request. By default all submitting elements (buttons and links) are disabled. Here's an example how to disable only inputs with type=submit (see below for more details):

<h:inputText value="#{myBean.text} id="text">
   <fry:ajax disableOnRequest="true" disableComponents="submit"
     event="onchange" reRender="componentX" action="onlyRoundtrip" />
</h:inputText>

For full Facelets support you need to use the J4Fry viewhandler. It doesn't do anything but provide access to the protected buildView method of the FaceletViewHandler. It is compatible with Facelets 1.1.14. Without using the J4Fry viewhandler you may experience that markup code outside of JSF tags is omitted by the AJAX rendering engine because the buildView method is needed to inject the markup into the component tree prior to rendering. Add this to your faces-config instead of the FaceletsViewHandler if you want to use the J4Fry ViewHandler:

  <view-handler>
    org.j4fry.jsf.J4FryViewHandler
  </view-handler>
</application>

J4Fry AJAX for JSF features

The J4Fry AJAX JSF solution works with a single tag that is nested inside any other JSF tag supporting Javascript events. You write your JSF application without using AJAX and later add AJAX functionality by nesting the J4Fry AJAX JSF tag inside a JSF tag refering the Javascript event you want to react on. The J4Fry AJAX tag will add the necessary Javascript functionality to the HTML code and the server side code will provide the required JSF answer.

In the event attribute you specify the Javascript event of the enclosing tag that should trigger the j4fry:ajax tag's action. Use the case-sensitive name of the enclosing tags attribute in the value of j4fry:ajax event attribute. This attribute is required. The AJAX's Javascript is added to any previous Javascript of the event. You can implement conditional AJAX by conditionally executing "return" in the Javascript code attached to the components event. Here's an example: A commandButton could have an onclick="if (!confirm('really delete?')) return;" and the nested fry:ajax would have event="onclick". The AJAX request will only happen if the user clicks "yes" into the dialog box.

The standard HTML JSF tags support these Javascript event attributes:

  • onclick
  • ondblclick
  • onkeydown
  • onkeypress
  • onkeyup
  • onmousedown
  • onmousemove
  • onmouseout
  • onmouseover
  • onmouseup

The action attribute specifies the JSF action to trigger on the server side when then Javascript event is triggered. This attribute is required.

The reRender attribute contains a comma separated list of id's of the JSF tags that are to be rerendered through AJAX. This attribute is required. It's also required that the JSF tags that are to be rerendered have their id attribute set.

The loadingBarId attribute references the HTML id of an HMTL element that should become visible during an AJAX request. It's a good idea to use an animated GIF here. The id you give here is NOT a JSF id (as it is in the rerender attribute. It is a HTML id as it shows up in the HMTL source code in the browser. Use h:graphicImage with binding="#{scriptHelper.bindings['myLoadingBar']" and refer to it with loadingBarId="#{scriptHelper.clientIdForBindings['myLoadingBar']". ScriptHelper is a JSF bean defined by J4Fry that delivers clientIds for JSF components to the JSF EL. Don't forget to set style="visibility:hidden" for your graphic image - it should only show up during AJAX requests!

Set attribute disableOnRequest to TRUE if you want to disable the Form elements on the HTML page while an AJAX request is running to hinder the user from submitting the page with a button durgin the request.
Possible values: TRUE, FALSE
Default is TRUE.

Using attribute disableComponents you have a fine granular control over the choice of components that are disabled with the disableOnRequest attribute. The attribute can take either comma separated keywords that specifiy groups of components or it can take a list of comma separated HTML IDs that are disabled during an AJAX request. It's not possible to mix keywords and component IDs, you have to use either or. If you want to use HTML ID's, you have to use the HTML-Element-IDs not the JSF-Tag-IDs. For setting the HTML-Element-IDs you may use a Apache-Tomahawk tag with the attribute 'forceId'. The possible keywords are: ALL, BUTTON, SUBMIT, RESET, TEXT, RADIO, CHECKBOX, SELECT, TEXTAREA, A. The attribute defaults to the keywords 'SUBMIT, RESET, BUTTON, A'.

With the preJSFunction attribute you can define Javascript code that is executed before the AJAX call is posted.

With the postJSFunction attribute you can define Javascript code that is executed after the AJAX call returns.

Please refer to the tlddoc for more details on the usage of the tag.

Here's a list of supportet features and technologies:

  • PPR (partial page rendering) picks single components out of the JSF tree and triggers their encode() methods.
  • PPS (partial page submit) submits only part of a form and reduces phases 2, 3, and 4 only to the submitted components.
  • Facelets support: We are using an extension of the FaceletsViewHandler to gain access to its buildView method and call it before encoding the components.
  • XHTML and HTML are equally well supported (especially the upper case/lower case differences for tag names).
  • Portlet support: When accessing the request (to determine the encoding) or the response (to acces the ResponseWriter) we check their types before casting and provide alternative portlet callbacks. We've tested doing AJAX inside a portal with liferay.
  • Portal support: When running in portals it may be inappropriate to access resouces through the classpath, so we provide a way to define the file path via web.xml.
  • JSF 1.1 and 1.2 comaptibility (tested with MyFaces 1.1.1, 1.1.5, 1.2 and JSF RI 1.2).
  • Queueing of AJAX requests.
  • During the AJAX request we offer a way to disable components either by Id or by type.
  • J4Fry AJAX accepts a loadingbar attribute pointing to an image that is to show up while the AJAX request is running.
  • To achieve compatibility with different JSF implementations we search for 5 different keys designating the JSF view state ("jsf_sequence", "jsf_tree_64", "jsf_viewid", "jsf_state_64", "javax.faces.ViewState").
  • We work around several flaws in IE to allow a cross-browser capable AJAX experience (use insertAdjacentHTML when createContextualFragment isn't available, parse response with VBScript if content-type=iso88591 instead of ISO-8859-1 and run contained scripts after replacing HTML elements).
  • We've tested AJAX on IE 5.5 - IE 7, FF 2-3, Safari and Opera.
  • The entire solution is designed and implemented to achieve high performance.
  • We've personally run J4Fry AJAX on Tomcat, BEA and Glassfish. Other users have tested on other application and web servers and we haven't heard of an incompatibility.