Updating portions of a web page with AJAX requests

Asynchronous JavaScript and XML (AJAX) is a development technique that you can use to create web pages that relay information to and from a server only for the portions of pages that users edit, while still displaying the rest of the page. This technique can make web applications faster and more efficient than if an entire page had to reload after each user action. You can set up an EGL-controlled JSP file to call the JSF Handler's onPreRenderFunction and provide a limited update to the page.

Setting up a JSP file and a JSF Handler to use AJAX requests involves these general steps:
  1. Create the page and JSF Handler.
  2. Design the page and populate the page with JSF controls that are bound to variables and functions in the JSF Handler.
  3. Indicate the area of the page that you want to change as a result of the AJAX request. No other part of the page will be affected.
  4. On the page, indicate the user event that will trigger the AJAX request, such as selecting or moving away from a particular text control.
  5. Define the request to send from the page to the JSF Handler, including the type of request (refresh, submit, or external) and any parameters to include with the request.
  6. Write code in the JSF Handler to process the request.
The following is the life cycle of a typical AJAX page in EGL:
  1. The servlet renders the complete page, running the functions indicated by the onConstructionFunction, onPreRenderFunction, and onPostRenderFunction JSF Handler properties, as applicable.
  2. The servlet sends the page to the browser.
  3. The user begins to fill out the input fields on the page.
  4. The user triggers the AJAX request.
  5. The browser sends the request to the servlet, including the parameters specified in the request.
  6. The servlet calls the function in the JSF Handler indicated by the onPreRenderFunction property, providing this function with the parameters in the request.
  7. The onPreRenderFunction function runs, updating controls in the area on the page specified by the AJAX request.
  8. The servlet renders the portion of the page specified by the AJAX request and updates this portion of the page in the browser.
  9. The cycle of AJAX requests continues until the user goes to another page, either by clicking a link or by triggering a forward statement in the JSF Handler.
There are three types of AJAX requests available to web pages in EGL:
Refresh
This type of request prompts the servlet to update the values of the controls in a specified area of the page; however, it does not provide information on the state of the page to the JSF Handler. In other words, if the user changes the value of input controls on the page, the JSF Handler is not aware of the changes; the variables in the JSF Handler are not updated to match the page controls to which the variables are bound. This limitation reduces the amount of data sent in the request, making the request more modular and efficient.

If the JSF Handler needs information from the page to complete the refresh request, you can add one or more parameters to the request. The JSF Handler receives these parameters along with the request, but as before, the variables in the JSF Handler are not updated to the new values of the controls to which the variables are bound. For more information, see Updating a page with a refresh request.

Submit
This type of request prompts the servlet to update the values of the controls in a specified area of the page, as well as to update the values of the variables in the JSF Handler. Unlike what happens in the refresh request, the submit request causes all of the variables in the JSF Handler to be set to the current values of the components to which the variables are bound. Therefore, it is not necessary to pass parameters with a Submit request, because all of the variables are updated to match the current state of the page. For more information, see Updating a page with a submit request.
External
This type of request prompts the servlet to update the content in a specified area of the page with content from a different page. For more information, see Updating a page with a portion of another page.

The J2EELib.getQueryParameter() system function retrieves the parameters from the AJAX request, if there are any. You can also use this function to detect whether the onPreRenderFunction function has been called as the result of an AJAX refresh or submit request by checking the value of the parameter $$ajaxmode. Any value other than NULL indicates that the function has been called as the result of an AJAX refresh or submit request:

if (J2EELib.getQueryParmeter("$$ajaxmode") == null)
  //Not the result of an AJAX refresh or submit request
  //May be the result of an AJAX external request or 
else
  //The result of an AJAX request.
end

Example

This example uses an AJAX refresh request to perform simple mathematical operations like a calculator. The page shows two input controls and a combo box with mathematical operations. The AJAX request, triggered by the combo box, passes the selected operation and the two input controls to the onPreRenderFunction of the JSF Handler, which performs the mathematical operation and updates an output control showing the answer.

The page might look like this example:

Picture of the page and AJAX behavior

The following is the code of the JSP file:

<html>
<head>
<title>calculatorPage</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="theme/stylesheet.css"
  title="Style">
</head>
<f:view>
  <body>
  <hx:scriptCollector id="scriptCollector1"
    preRender="#{calculatorPage._preRender}"
    postRender="#{calculatorPage._postRender}">

<h:form id="form1" styleClass="form">
<TABLE>
<TBODY>
  <tr>
  <td align="left">Field1:</td>
  <td style="width:5px"></td>
  <td>
    <h:inputText id="input1" value="#{calculatorPage.field1}"
      binding="#{calculatorPage.field1_Ref}" styleClass="inputText">
    </h:inputText>
  </td>
  </tr>
  <tr>
  <td align="left">Field2:</td>
  <td style="width:5px"></td>
  <td>
    <h:inputText id="input2" value="#{calculatorPage.field2}"
      binding="#{calculatorPage.field2_Ref}" styleClass="inputText">
    </h:inputText>
  </td>
  </tr>
  <tr>
  <td align="left">Operation:</td>
  <td style="width:5px"></td>
  <td>
    <h:selectOneMenu id="operationComboBox"
      styleClass="selectOneMenu" value="#{calculatorPage.operation}">
      <f:selectItem itemValue="add" itemLabel="add" />
      <f:selectItem itemValue="subtract" itemLabel="subtract" />
      <f:selectItem itemValue="multiply" itemLabel="multiply" />
      <f:selectItem itemValue="divide" itemLabel="divide" />
    </h:selectOneMenu>
    <hx:behavior event="onblur"
      target="operationComboBox" behaviorAction="get" 
      targetAction="updatablePanel"></hx:behavior></td>
  </tr>
  <tr>
  <td align="left">Output:</td>
  <td style="width:5px"></td>
  <td>
    <h:panelGroup id="updatablePanel" styleClass="panelGroup">
      <h:outputText id="output" value="#{calculatorPage.output}"
        binding="#{calculatorPage.output_Ref}" styleClass="outputText">
      </h:outputText>
    </h:panelGroup>
    <hx:ajaxRefreshRequest id="ajaxRefreshRequest1"
      target="updatablePanel" params="input1;input2;operationComboBox">
    </hx:ajaxRefreshRequest>
  </td>
  </tr>

</TBODY>
</TABLE>
</h:form>
  </hx:scriptCollector>
  </body>
</f:view>
</html>

The following is the code of the JSF Handler that goes with this page:

package jsfhandlers;

handler calculatorPage type JSFHandler
  {onPreRenderFunction = onPreRender, 
    view = "calculatorPage.jsp"} 
    
    field1 float;
    field2 float;
    operation string;
    output string;

  function onPreRender()
    
    if (J2EELib.getQueryParameter("$$ajaxmode") == null)
      output = "Enter values and an operation.";
    else
      calculateAnswer();
    end
    
  end
  
  function calculateAnswer()
    param1 float = J2EELib.getQueryParameter("input1");
    param2 float = J2EELib.getQueryParameter("input2");
    
    case (J2EELib.getQueryParameter("operationComboBox"))
      when ("add")
        output = param1 + param2;
      when ("subtract")
        output = param1 - param2;
      when ("multiply")
        output = param1 * param2;
      when ("divide")
        output = param1 / param2;
    end
  end
end