-
Notifications
You must be signed in to change notification settings - Fork 15
Ajax 2.x
TOCSTART
TOCEND
Ajax component is a non-visual component that makes it possible to submit and reload any JSF components with Ajax and perform server actions without reloading the whole page.
- Reloading components with Ajax
- Invoking server action during an Ajax request
- Loading data from the server during an Ajax request
- Controlling submitted data
- Avoiding frequent requests
- Ajax state events
- Standalone mode
- Pure JavaScript API
The common use-case for implementing interactive Ajax features is when there's a component on a page that triggers some action that requires an Ajax call to the server. For this purpose, the Ajax component has a feature of attaching it to the "invoker" component, or a component that initiates the Ajax action. For example it is possible to attach the Ajax component to a button component, and even more, it is possible to attach to arbitrary HTML tags that are not JSF components.
There are two ways of attaching to a component:
- It can be placed right into the invoker component's tag. This way is simpler for most cases when you need to
attach to a JSF component. Here's an example:
<h:inputText> <o:ajax event="keypress" render="ajaxOutput"/> </h:inputText>
- You can place a component anywhere and specify its for attribute that refers to a
component that Ajax component should be attached to. This way can be used to attach not just to a
JSF component as in the previous point, but to an arbitrary HTML element by its client identifier, see below.
Here's an example of attaching to a "click" event of the HTML <button>
tag:
<button id="editData">Test</button> <o:ajax for=":editData" render="ajaxOutput"/>
In both cases you can use the event attribute to specify the attached component's event that will determine when Ajax request should be executed. The default value for this attribute is "click", which means that Ajax request will be initiated when a user clicks on the attached component. Note that the event string should be without the "on" prefix, for example you should use "dblclick" instead of "ondblclick".
The render attribute should specify ids for all components that should be reloaded during the Ajax request. A value expression should evaluate to a Iterable of String, if a literal is specified the identifiers must be space delimited.
The for attribute mentioned in the second point should be assigned with the id of a JSF component or id of any HTML element, whose event should be listened to:
- The first way of specifying this attribute is for referencing JSF components and it is similar to the way of specifying the for attribute of the standard <h:outputLabel> and <h:message> tags. It can either be an "absolute" identifier that begins with a colon and includes ids of all naming container parents, such as ":form:button1", or it can be a relative identifier that refers to another child in the same naming container, for example "button2". The formal rules of finding the component by identifier are described in API reference for the UIComponent.findComponent() method.
- The second way of specifying this attribute is for referring HTML elements rather than JSF components. Referring to HTML elements is similar to referring JSF components with an absolute identifier – you just need to prepend actual element id with a colon symbol. For example in order to refer a an HTML button tag declared as <input id="myHtmlButton" type="button" value="Test"/> you should use the ":myHtmlButton" value of the for attribute.
Note that it is not possible to change the rendered attribute of the reloaded component(s) since that change cannot not be applied during the Ajax request. This limitation is applicable only to the components specified for reloading directly and not to their child components. So this issue can be solved by wrapping the component whose rendered attribute is being changed into any container (for example the <h:panelGroup> component) and reloading that container instead.
There is a possibility of invoking a server action during an Ajax request. This can be made using the listener attribute. This attribute should be specified as a method binding expression pointing at an action listener to be invoked. The phase when the action is invoked depends on the value of the immediate attribute (see the Controlling Phase of Action Execution section below). The referred method should receive one parameter of type javax.faces.event.AjaxBehaviorEvent (or javax.faces.event.ActionEvent if you're using OpenFaces 2.x).
Phase of action listener notification is controlling by the immediate attribute. If attribute is equal to true, then action will be invoke during Apply Request Values phase. If attribute equals false (the default value), then action will be invoked in Invoke Application phase.
Any Ajax action performed using the Ajax component will usually need some data entered on the page to be submitted to the server for processing.
Here are the rules that are used to determine the components whose data should be submitted and processed on the server:
- All reloaded components specified in the render attribute are submitted to the server (unless the executeRenderedComponents attribute is set to false as described below).
- If Ajax component is attached to some component (i.e. not configured as using a stand-alone mode, see below), then the attached component is submitted in addition to all other submitted components, though this component won't be reloaded unless it is included into the render attribute explicitly.
- It is possible to specify the list of components that should be submitted in addition to the ones mentioned above by explicitly specifying their ids in the execute attribute. These components will be submitted to the server for processing their data, but they won't be reloaded as a result of Ajax request. This feature is useful for a quite common case when the reloaded components and/or the executed action depends on the data entered elsewhere on the page.
Here is an example where a button reloads an <h:outputText> component with the text entered in an <h:inputText> component without reloading the input component.
<h:inputText id="input1" value="#{requestScope['text1']}"> <o:ajax event="keypress" render="ot1" execute="it1"/> </h:inputText> <h:commandButton value="Test"> <o:ajax render="input1" execute="output1"/> </h:commandButton> <h:outputText id="output1" value="#{requestScope['text1']}"/>
Note that by default all components specified in the render attribute undergo the "execute" lifecycle as well, just as if they are implicitly included into the execute attribute. This means that their Restore View, Apply Request Values, Process Validations and Update Model Values phases are being executed. You can prevent this behavior executeRenderedComponents attribute to false, so these components will just be re-rendered without validation and saving their data to backing bean.
In some cases the Ajax component event can be attached to an event that might occur quite frequently, and it becomes reasonable to make fewer requests in such cases. For example consider an input field that triggers Ajax reload when the user types a key. It is possible to configure the Ajax component to send a request once the user stops typing in a text field for a while. The delay attribute specifies a delay in milliseconds that should elapse after an event before starting an actual request. Subsequent request during this delay will make the request to be postponed until the specified delay elapses after the last such event.
Below is an example of using the delay attribute to send a request every time the user stops typing in a text field for one second.
<h:inputText> <o:ajax event="keypress" render="reloadedComponent" delay="1000"/> </h:inputText>
Tag supports all events of components – the standard ones, such as onclick, onmouseup etc., and component-specific, such as onadd for TwoListSelection or onchange for DataTable's selection. The usage is the same in both cases, though please note that attaching to custom component events are not supported when Ajax component is attached to the "invoker" component with the for attribute. Therefore you should either attach a component by embedding it into the appropriate tag, or use client-side API (see below) if you need to use Ajax reloading for component-specific events. Here's an example:
<o:twoListSelection> <f:selectItems value="#{SomeExampleBean.items}"/> <o:ajax event="add" render="selectedOutput"/> </o:twoListSelection>
There is a possibility to receive notifications of various conditions of the Ajax request using the following event attributes of the <o:ajax> tag:
- onevent – specifies a JavaScript code that should be executed when event specified in the event attribute occurred.
- onajaxstart – specifies a JavaScript code that should be executed before Ajax request is sent.
- onajaxend – specifies a JavaScript code that should be executed after receiving of Ajax response. The event parameter for this event has an additional validationError boolean flag and ajaxResult property, which is described in the LoadingData with Ajax section below.
- onerror – specifies a JavaScript code that should be executed when any error has occurred during execution of Ajax request.
- onsuccess (currently available only for 3.x version) -- specifies a JavaScript code that should be executed execution of Ajax request was successful and no exceptions occurred. Please note that even if JSF data validation failed but there were no other errors Ajax request would be considered successful. The event parameter for this event has an additional validationError boolean property to determine if there were validation errors.
Besides executing a server action and reloading components during the Ajax request, it is also possible to send data from the server as part of the Ajax request. The data that should be sent to the client can be specified by the Ajax event listener in two ways:
- You can to declare the Ajax action listener method with the AjaxActionEvent parameter (instead of the usual AjaxBehaviorEvent type which is also allowed when declaring Ajax action listener method), and specify the required value by invoking its setAjaxResult method.
- You can specify the desired value in the ajaxResult property of the AjaxRequest class.
The value specified using these methods, or the "ajaxResult" value, can be of one of the following types:
- any primitive type wrapper (java.lang.Integer, java.lang.Boolean, etc...);
- java.lang.String;
- a collection or an array of any of the types listed here;
- a map with string keys and values of any of the types listed here.
The "ajaxResult" value will be available in the ajaxResult property of the onajaxend event of the corresponding Ajax request. The primitive and string types will be represented with their JavaScript analogs, collections and arrays will be represented as JavaScript arrays, and maps will be represented with JavaScript objects, where each key/value pair will be represented with an appropriate object's field.
There are use cases when Ajax component shouldn't be bound to a component explicitly, but should be available for explicit invocation from a JavaScript code. This can for example be needed when the same Ajax request should be executed when receiving events from several components on a page, or when it should be executed upon a specific condition that can only be detected with JavaScript.
Such use cases can be addressed by adding the standalone attribute with a value of true to the <o:ajax> tag, and specifying its id attribute to be able to refer this component from a JavaScript code. The <o:ajax> tag itself in this case can reside in any part of the page like any other JSF component, though as a non-visual component it won't affect page rendering and will just be available through the JavaScript code. The functionality of the Ajax component in this case can be activated by invoking the run() JavaScript function on the Ajax component instance.
Here's an example that invokes the same Ajax component upon different events of several components:
<h:form id="form"> <h:inputText id="textField" onkeypress="O$('form:updateImage').run()" .../> <h:selectOneMenu id="colorField" onchange="O$('form:updateImage').run()" ...> ... </h:selectOneMenu> <o:dropDownField id="fontSizeField" onchange="O$('form:updateImage').run()" ...> ... </o:dropDownField><o:ajax id="updateImage" standalone="true" render="dynamicImage" execute="textField colorField fontSizeField" requestDelay="500"/>
<o:dynamicImage id="dynamicImage" .../> </h:form>
The standalone mode described in the previous section allows invoking Ajax component functionality explicitly from the JavaScript, though it requires the Ajax component to be present and configured on the page. In addition to this facility, it is possible to invoke the functionality of the Ajax component purely with JavaScript code, without declaring the component on a page. This can be achieved using the O$.ajax.request(source, event, options) JavaScript function, which provides a functionality identical to the <o:ajax> tag right from JavaScript.
The function receives the following arguments:
- source – a string identifier or a reference to the element that invokes this request.
- event (optional) – an event object that triggered this request.
- options – (optional) an object, which consist of:
- render – (required) a space separated list of component client id(s) that should be reloaded.
- execute – (optional) a space separated list of component client id(s) for components whose processDecodes ->...-> processUpdates phases should be executed in addition to the component being reloaded.
- executeRenderedComponents – (optional) a boolean parameter with a default value of true specifying whether the "execute" portion of lifecycle should be executed for the reloaded component(s).
- listener – (optional) server action listener in the form of EL, which should be executed during this Ajax request. It is written in a convention BeanName.functionName, similar to the listener attribute of <o:ajax> tag, though without the #{ and } parts.
- immediate – (optional) true means that the serverAction should be executed during Apply Request Values phase, rather than waiting until the Invoke Application phase.
- delay – (optional) an analog of the delay attribute of <o:ajax> tag. Specifies a delay in milliseconds that allows minimizing sending frequent Ajax requests as described in the Avoiding Frequent Requests section.
- onajaxstart – (optional) the function that should be invoked before Ajax request is started.
- onajaxend – (optional) the function that should be invoked when Ajax request is fully processed.
- onerror – (optional) the function that should be invoked when Ajax request fails to complete successfully for some reason.
- onsuccess – (optional) the function that should be invoked before Ajax request is completed successfully (available in 3.x only).
- params – (optional) an object containing the additional request parameters
Here's an example:
<h:outputText id="ajaxOutput1" value="#{SomeBean.outputText1}"/> <h:outputText id="ajaxOutput2" value="#{SomeBean.outputText2}"/> <h:inputText id="ajaxInput" onkeypress="O$.ajax.request(this, event, { render: 'form1:ajaxOutput1 form1:ajaxOutput2', execute: 'form1:ajaxInput', listener: 'SomeBean.someAction', onajaxend: function() {alert('Success!')} })"/>
Note that all components should be located in the same form.
If you're using the O$.ajax.request function and there are no other Ajax-capable OpenFaces components on the page, you'll need to place the <o:ajaxSettings/> component on the page for JavaScript library where the O$.ajax.request function is defined to be available on the page.