Updating Single Components Using the fireAjaxTransaction Function
One of the JavaScript functions that Dynamic Faces provides is the fireAjaxTransaction function. As its name suggests, it initiates an Ajax request when it is invoked.
Dynamic Faces automatically attaches fireAjaxTransaction functions on certain components within an Ajax zone. But, you can manually attach fireAjaxTransaction functions on individual components in the page so that an Ajax request is initiated when the component is activated. As a result, this function gives you finer-grained, component-level control over what is updated in your page. To use the fireAjaxTransaction function with a component, you do the following:
Add a JavaScript event attribute, such as onclick, to a component tag.
Set the value of the attribute to the DynaFaces.fireAjaxTransaction function.
Pass a set of parameters to the function.
The fireAjaxTx.jsp page of the simpleDynamicFaces application uses fireAjaxTransaction to do the following:
Asynchronously update the menu of varieties and the variety description when the user selects a new fruit.
Asynchronously update the variety description when the user selects a different variety from the variety menu.
The following piece of fireAjaxTx.jsp shows how the fruit and variety components use fireAjaxTransaction to update components using Ajax:
<f:view> ... <h:form prependId="false" id="form"> ... <h:panelGrid columns="2" cellpadding="4"> <h:outputText value="Select a fruit:"/> <h:outputText value="Select a variety:"/> <h:selectOneRadio id="fruit" value="#{fruitInfoBean.fruit}" onclick="DynaFaces.fireAjaxTransaction(this, { execute: 'fruit'});" valueChangeListener="#{fruitInfoBean.changeFruit}"> <f:selectItems value="#{fruitInfoBean.fruits}"/> </h:selectOneRadio> <h:selectOneMenu id="variety" value="#{fruitInfoBean.variety}" onchange="DynaFaces.fireAjaxTransaction(this, { execute: 'variety' });" valueChangeListener="#{fruitInfoBean.updateVariety}"> <f:selectItems value="#{fruitInfoBean.varieties}"/> </h:selectOneMenu> </h:panelGrid> <h:outputText id="varietyInfo" value="#{fruitInfoBean.varietyInfo}" /> </h:form> ... </f:view>
As the preceding markup shows, the fruit component has an onclick JavaScript event attribute, and the variety component has an onchange JavaScript event attribute. These attributes are set to a fireAjaxTransaction function call. When the user clicks one of these components, the following happens:
The DynaFaces.fireAjaxTransaction function executes, causing Dynamic Faces to initiate an Ajax request to the server.
The server returns a special XML response that the Dynamic Faces JavaScript library processes.
The appropriate library functions update the HTML DOM tree with the newly rendered values.
To tell the fireAjaxTransaction function how to produce the Ajax request, you pass a set of parameters to it. Here is the call to fireAjaxTransaction from the fruit component:
DynaFaces.fireAjaxTransaction(this, { execute: 'fruit'});
In the case of the preceding example, you pass two parameters to the fireAjaxTransaction function. The this parameter is a JavaScript reference to the DOM element that represents the fruit component in the rendered markup generated by the fruit selectOneRadio tag.
The other parameter is a kind of JavaScript Object known as an associative array, in which the keys are strings and the values are whatever you want them to be. Each key/value pair represents an option that you pass to the fireAjaxTransaction function. These options tell Dynamic Faces which parts of the component tree it needs to process and re-render using Ajax.
The Dynamic Faces JavaScript Library Reference includes the complete list of acceptable options. In this case, the only option is execute: 'fruit', which says that the fruit component (and its children, if it has any) must go through the execute portion of the JavaServer Faces life cycle. This part of the life cycle includes the phases responsible for converting and validating data, updating model values, and handling action events.
On the server side, the changeFruit method of FruitInfoBean responds to the value-change event registered on the fruit component. This method performs model updates of other components in the tree, just as it does in any regular JavaServer Faces application. Therefore, the fruit component must go through the execute phase of the life cycle so that these updates can occur. The following code snippet shows the changeFruit value-change event handler method. As you can see, there is nothing different you have to do in this method or any other part of your server-side code to use Dynamic Faces with your JavaServer Faces application:
public void changeFruit(ValueChangeEvent e){ String fruitValue = (String)e.getNewValue(); String[] varieties = getFruitVarieties(fruitValue); setVarietyInfo(fruitMessages.getString(varieties[0])); setVariety(varieties[0]); ... }
Another common option to pass with the fireAjaxTransaction function is the render option, which you use to indicate which components should be re-rendered when the Ajax transaction is completed. You don't need the render option in this example because you want all components to be re-rendered as a result of this action, which is the default behavior.
Supposing that the user selects Apple from the set of choices in the radio button group, the following happens:
The fireAjaxTransaction function is called with the options to send the fruit component through the execute phase of the life cycle and the rest of the tree through the render phase of the life cycle.
The fruit component goes through the execute phase of the life cycle, and the value-change event that is registered on it is fired. The valueChangeListener attribute of the fruit component tag references the changeFruit method, which handles the value-change event. This step would take place in a regular JavaServer Faces application.
The changeFruit method gets the value, Apple, from the fruit component, which fired the event, updates the model value of the variety menu component with the list of apple varieties, and sets the selected value of the variety component to Adanac.
The changeFruit method also updates the model value varietyInfo component, which displays the description of the selected variety. In this case, the selected variety is Adanac, and so the description is “Adanac: Suitable for desserts. Green and red striped skin. Resistant to harsh winter weather.”
Dynamic Faces re-renders the DOM tree, replacing the selected DOM elements with the new values.
The fireAjaxTransaction call that occurs when a user selects a variety from the variety component works in a similar way. It causes the variety component to go through the execute phases of the life cycle. While this happens, the value-change event listener, updateVariety updates the varietyInfo model value with the description that matches the selected variety. Then Dynamic Faces re-renders the varietyInfo component with the new description.
Updating Individual DOM Elements Using installDeferredAjaxTransaction
As the previous section explained, you can use fireAjaxTransaction to asynchronously update individual components. Although the simpleDynamicFaces application uses this function in combination with a user-initiated event, you can use the fireAjaxTransaction in non-event-driven situations when you include it inside the script elements in the page. In this situation, the function is called immediately rather than in response to a user-initiated event.
The installDeferredTransaction function is an extension of the fireAjaxTransaction function. Rather than executing immediately, the installDeferredTransaction function installs a fireAjaxTransaction onto a DOM element that will be called when a specified event occurs on that DOM element.
One situation that calls for usage of installDeferredTransaction is when you want to install a deferred Ajax transaction on a piece of markup generated by a component rather than on the entire component. For example, the Java Blueprints team provides a table scroller component that generates a set of <a> tags in which each tag points to a different set of tabular data in the same table, thereby allowing a user to page through the data set by clicking on a link represented by an <a> tag. Because the page author does not know when authoring the page what <a> tags will be rendered from the component, she cannot install Ajax transactions on these elements. Instead, she can write some JavaScript that will install deferred Ajax transactions on these elements during script execution time, which occurs after the <a> tags are already rendered.
The simpleDynamicFaces application demonstrates a simpler use case of installDeferredAjaxTransaction in which the function installs deferred Ajax transactions on input tags that are rendered from a selectOneRadio component. In this case, the application asks the user to select the correct option to win a prize. If the user selects the correct option, the application displays the message, “You are correct. Get 20% off Peaches at Duke's Fruit Stand. Use coupon number GTH056.”
The following code from the installDeferred.jsp page of the application shows the tag representing the fruitQuiz component from which the user selects the correct answer, the answerMessage component tag that displays the message, and the script that installs the deferred Ajax transaction.
... <h:outputText value="Select the true statement to win a prize:"/> <h:selectOneRadio id="fruitQuiz" value="#{fruitInfoBean.fruitQuiz}" layout="pageDirection" valueChangeListener="#{fruitInfoBean.gradeFruitQuiz}"> <f:selectItem itemLabel="Peaches originate from China" itemValue="peaches"/> <f:selectItem itemLabel="Apples sink in water" itemValue="apples"/> </h:selectOneRadio> <h:outputText id="answerMessage" value="#{requestScope.answerMessage}" />. </h:form> ... <script> var trueValue = null; trueValue = document.getElementById("fruitQuiz:0"); DynaFaces.installDeferredAjaxTransaction(trueValue, 'click', {execute: 'fruitQuiz', render: 'answerMessage' }); </script>
When the preceding page is rendered, the first choice from the selectOneRadio component will be rendered as an input tag with the ID fruitQuiz:0. The first choice is the correct answer, so when the user selects it, the installed deferred Ajax transaction is fired. When this happens, the fruitQuiz component goes through the execute phase of the life cycle, during which time the gradeFruitQuiz value-change event listener method executes. If the user selected the correct value, this method sets the model value of the answerMessage component to the “winning” message:
public void gradeFruitQuiz(ValueChangeEvent e) { String answer = (String)e.getNewValue(); String answerMessage = null; if (answer.equals("peaches")) { answerMessage = "You are correct. Get 20% off Peaches at Duke's Fruit Stand. " + "Use coupon number GTH056."; } FacesContext.getCurrentInstance() .getExternalContext() .getRequestMap() .put("answerMessage", answerMessage); }
If the user selects the false option, the fruitQuiz component is not executed and no message will display.