This chapter describes how to handle events on the server as well as on the client.
This chapter includes the following sections:
In traditional JSF applications, event handling typically takes place on the server. JSF event handling is based on the JavaBeans event model, where event classes and event listener interfaces are used by the JSF application to handle events generated by components.
Examples of user events in an application include clicking a button or link, selecting an item from a menu or list, and changing a value in an input field. When a user activity occurs such as clicking a button, the component creates an event object that stores information about the event and identifies the component that generated the event. The event is also added to an event queue. At the appropriate time in the JSF lifecycle, JSF tells the component to broadcast the event to the appropriate registered listener, which invokes the listener method that processes the event. The listener method may trigger a change in the user interface, invoke backend application code, or both.
Like standard JSF components, ADF Faces command components deliver ActionEvent
events when the components are activated, and ADF Faces input and select components deliver ValueChangeEvent
events when the component local values change.
For example, in the File Explorer application, the File Menu contains a submenu whose commandMenuItem
components allow a user to create a new file or folder. When users click the Folder commandMenuItem
, an ActionEvent
is invoked. Because the EL expression set as the value for the component's actionListener
attribute resolves to the createNewDirectory
method on the headerManager
managed bean, that method is invoked and a new directory is created.
Note:
Any ADF Faces component that has built-in event functionality must be enclosed in theform
tag.While ADF Faces adheres to standard JSF event handling techniques, it also enhances event handling in two key ways by providing:
Ajax-based functionality (partial page rendering)
A client-side event model
Unlike standard JSF events, ADF Faces events support AJAX-style partial postbacks to enable partial page rendering (PPR). Instead of full page rendering, ADF Faces events and components can trigger partial page rendering, that is, only portions of a page refresh upon request.
Certain components are considered event root components. Event root components determine boundaries on the page, and so allow the lifecycle to run just on components within that boundary (for more information about this aspect of the lifecycle, see Section 4.3, "Using the Optimized Lifecycle"). When an event occurs within an event root, only those components that are children to the root are refreshed on the page. An example of an event root component is a popup. When an event happens within a popup, only the popup and its children are rerendered, and not the whole page.
Additionally, certain events indicate a specific component as an event root component. For example, the disclosure event sent when a expanding or collapsing a showDetail
component (see Section 8.8, "Displaying and Hiding Contents Dynamically"), indicates that the showDetail
component is a root. The lifecycle is run only on the showDetail
component (and any child components or other components that point to this as a trigger), and only they are rerendered when it is expanded or collapsed.
Table 5-1 shows the event types in ADF Faces, and whether or not the source component is an event root.
Table 5-1 Events and Event Root Components
Event Type | Component Trigger | Is Event Root |
---|---|---|
|
All command components |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
All command components |
NA |
|
|
|
|
|
NA |
|
|
|
|
|
NA |
|
|
NA |
|
|
NA |
|
All components |
NA |
|
|
|
|
|
|
|
|
NA |
|
|
NA |
|
All command components |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
All input and select components (components that implement |
|
Tip:
If components outside of the event root need to be processed when the event root is processed, then you must set thepartialTrigger
attribute on those components to the ID of the event root component.In addition to server-side action and value change events, ADF Faces components also invoke client-side action and value change events, and other kinds of server and client events. Some events are generated by both server and client components (for example, selection events); some events are generated by server components only (for example, launch events); and some events are generated by client components only (for example, load events).
By default, most client events are propagated to the server. Changes to the component state are automatically synchronized back to the server to ensure consistency of state, and events are delivered, when necessary, to the server for further processing. However, you can configure your event so that it does not propagate.
In addition, any time you register a client-side event listener on the server-side Java component, the RCF assumes that you require a JavaScript component, so a client-side component is created.
Client-side JavaScript events can come from several sources: they can be derived automatically from DOM events, from property change events, or they can be manually created during the processing of other events.
ADF Faces provides a number of server-side events. Table 5-2 lists the events generated by ADF Faces components on the server, and the components that trigger them.
Table 5-2 ADF Faces Server Events
Event | Triggered by Component... |
---|---|
|
All command components |
|
|
|
|
|
|
|
All command components |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
All command components |
|
|
|
|
|
|
|
|
|
All input and select components (components that implement |
* This focus event is generated when focusing in on a specific subtree, which is not the same as a client-side keyboard focus event.
** The LoadEvent
event is fired after the initial page is displayed (data streaming results may arrive later).
All server events have event listeners on the associated component(s). You need to create a handler that processes the event and then associate that handler code with the listener on the component.
For example, in the File Explorer application, a selection event is fired when a user selects a row in the table. Because the table's selectionListener
attribute is bound to the tableSelectFileItem
handler method on the TableContentView.java
managed bean, that method is invoked in response to the event.
In a managed bean (or the backing bean for the page that will use the event listener), create a public method that accepts the event (as the event type) as the only parameter and returns void
. Example 5-1 shows the code for the tableSelectFileItem
handler. (For information about creating and using managed beans, see Section 2.6, "Creating and Using Managed Beans.")
Example 5-1 Event Listener Method
public void tableSelectFileItem(SelectionEvent selectionEvent) { FileItem data = (FileItem)this.getContentTable().getSelectedRowData(); setSelectedFileItem(data); }
Tip:
If the event listener code is likely to be used by more than one page in your application, consider creating an event listener implementation class that all pages can access. All server event listener class implementations must override aprocessEvent()
method, where Event
is the event type.
For example, the LaunchListener
event listener accepts an instance of LaunchEvent
as the single argument. In an implementation, you must override the event processing method, as shown in the following method signature:
public void processLaunch (LaunchEvent evt) { // your code here }
To register an event listener method on a component, in the Structure window, select the component that will invoke the event. In the Property Inspector, use the dropdown menu next to the event listener property, and choose Edit.
Use the Edit Property dialog to select the managed bean and method created in Step 1.
Example 5-2 shows sample code for registering a selection event listener method on a table
component.
Most components can also work with client-side events. Handling events on the client saves a roundtrip to the server. When you use client-side events, instead of having managed beans contain the event handler code, you use JavaScript, which can be contained either on the calling page or in a JavaScript library.
By default, client events are processed only on the client. However, some event types are also delivered to the server, for example, AdfActionEvent
events, which indicate a button has been clicked. Other events may be delivered to the server depending on the component state. For example, AdfValueChangeEvent
events will be delivered to the server when the autoSubmit
attribute is set to true
. You can cancel an event from being delivered to the server if no additional processing is needed. However, some client events cannot be canceled. For example, because the popupOpened
event type is delivered after the popup window has opened, this event delivery to the server cannot be canceled.
Performance Tip:
If no server processing is needed for an event, consider canceling the event at the end of processing so that the event does not propagate to the server. For more information, see Section 5.3.5, "How to Prevent Events from Propagating to the Server."Table 5-3 lists the events generated by ADF Faces client components, whether or not events are sent to the sever, whether or not the events are cancelable, and the components that trigger the events.
Table 5-3 ADF Faces Client Events
Event Type | Event Class | Propagates to Server | Can Be Canceled | Triggered by Component |
---|---|---|---|---|
|
|
Yes |
Yes |
All command components |
|
|
Yes |
Yes |
When user selects the OK or Cancel button in a dialog |
|
|
Yes |
Yes |
When the disclosure state is toggled by the user |
|
Yes |
Yes |
|
|
|
Yes |
Yes |
|
|
|
|
Yes |
Yes |
When the internal |
|
|
Yes |
Yes |
After the document's contents have been displayed on the client, even when PPR navigation is used. It does not always correspond to the onLoad DOM event. |
|
Yes |
Yes |
|
|
|
|
No |
No |
After a popup window or dialog is opened |
|
|
No |
Yes |
Prior to opening a popup window or dialog |
|
|
No |
No |
After a popup window or dialog is closed |
|
|
No |
No |
All components |
|
|
Yes |
Yes |
Upon a query action (that is, when the user clicks the search icon or search button) |
|
|
Yes |
Yes |
|
|
Yes |
Yes |
All command components |
|
|
Yes |
Yes |
|
|
|
Yes |
Yes |
|
|
|
|
Yes |
Yes |
When the row disclosure state is toggled |
|
|
Yes |
Yes |
When the selection state changes |
|
|
Yes |
Yes |
When the user sorts the table data |
|
|
Yes |
Yes |
All input and select components (components that implement When the value of an input or select component is changed |
ADF Faces also supports client keyboard and mouse events, as shown in Table 5-4
Table 5-4 Keyboard and Mouse Event Types Supported
Event Type | Event Fires When... |
---|---|
|
User clicks a component |
|
User double-clicks a component |
|
User moves mouse down on a component |
|
User moves mouse up on a component |
|
User moves mouse while over a component |
|
Mouse enters a component |
|
Mouse leaves a component |
|
User presses key down while focused on a component |
|
User releases key while focused on a component |
|
When a successful keypress occurs while focused on a component |
|
Component gains keyboard focus |
|
Component loses keyboard focus |
Best Practice:
Keyboard and mouse events wrap native DOM events using theAdfUIInputEvent
subclass of the AdfBaseEvent
class, which provides access to the original DOM event and also offers a range of convenience functions for retrieval of key codes, mouse coordinates, and so on. The AdfBaseEvent
class also accounts for browser differences in how these events are implemented. Consequently, you must avoid invoking the getNativeEvent()
method on the directly, and instead use the AdfUIInputEvent
API.The clientListener
tag provides a declarative way to register a client-side event handler script on a component. The script will be invoked when a supported client event type is fired. Example 5-3 shows an example of a JavaScript function associated with an action event.
Example 5-3 clientListener Tag
<af:commandButton id="button0" text="Do something in response to an action"> <af:clientListener method="someJSMethod" type="action"/> </af:commandButton>
Tip:
Use theclientListener
tag instead of the component's JavaScript event properties.To use client-side events, you need to first create the JavaScript that will handle the event. You then use a clientListener
tag.
Create the JavaScript event handler function. For information about creating JavaScript, see Section 3.3, "Adding JavaScript to a Page." Within that functionality, you can add the following:
Locate a client component on a page
If you want your event handler to operate on another component, you must locate that component on the page. For example, in the File Explorer application, when users choose the Give Feedback menu item in the Help menu, the associated JavaScript function has to locate the help popup dialog in order to open it. For more information about locating client components, see Section 3.5, "Locating a Client Component on a Page."
Return the original source of the event
If you have more than one of the same component on the page, your JavaScript function may need to determine which component issued the event. For example, say more than one component can open the same popup dialog, and you want that dialog aligned with the component that called it. You must know the source of the AdfLaunchPopupEvent
in order to determine where to align the popup dialog. For more information, see Section 5.3.2, "How to Return the Original Source of the Event."
Add client attributes
It may be that your client event handler will need to work with certain attributes of a component. For example, in the File Explorer application, when users choose the About menu item in the Help menu, a dialog launches that allows users to provide feedback. The function used to open and display this dialog is also used by other dialogs, which may need to be displayed differently. Therefore, the function needs to know which dialog to display along with information about how to align the dialog. This information is carried in client attributes. Client attributes can also be used to marshall custom server-side attributes to the client. For more information, see Section 5.3.3, "How to Use Client-Side Attributes for an Event."
Cancel propagation to the server
Some of the components propagate client-side events to the server, as shown in Table 5-3. If you do not need this extra processing, then you can cancel that propagation. For more information, see Section 5.3.5, "How to Prevent Events from Propagating to the Server."
Once you create the JavaScript function, you must add an event listener that will call the event method.
Note:
Alternatively, you can use a JSF 2.0 client behavior tag (such asf:ajax
) to respond to the client event, as all client events on ADF Faces components are also exposed as client behaviors. For more information, see the Java EE 6 tutorial (http://download.oracle.com/javaee/index.html
)Select the component to invoke the JavaScript, and in the Property Inspector, set ClientComponent to true.
In the Component Palette, from the Operations panel, drag a Client Listener and drop it as a child to the selected component.
In the Insert Client Listener dialog, enter the method and select the type for the JavaScript function.
The method
attribute of the clientListener
tag specifies the JavaScript function to call when the corresponding event is fired. The JavaScript function must take a single parameter, which is the event object.
The type
attribute of the clientListener
tag specifies the client event type that the tag will listen for, such as action
or valueChange
. Table 5-3 lists the ADF Faces client events.
The type
attribute of the clientListener
tag also supports client event types related to keyboard and mouse events. Table 5-4 lists the keyboard and mouse event types.
Example 5-4 shows the code used to invoke the showHelpFileExplorerPopup
function from the Explorer.js
JavaScript file.
Add any attributes required by the function by dragging a Client Attribute from the Operations panel of the Component Palette, and dropping it as a child to the selected component. Enter the name and value for the attribute in the Property Inspector. Example 5-5 shows the code used to set attribute values for the showAboutFileExplorerPopup
function.
<af:commandMenuItem id="aboutMenuItem" text="#{explorerBundle['menuitem.about']}" clientComponent="true"> <af:clientListener method="Explorer.showAboutFileExplorerPopup" type="action"/> <af:clientAttribute name="popupCompId" value=":fe:aboutPopup"/> <af:clientAttribute name="align" value="end_after"/> <af:clientAttribute name="alignId" value="aboutMenuItem"/> </af:commandMenuItem>
Note:
If you use theattribute
tag (instead of the clientAttribute
tag) to add application-specific attributes or bonus attributes to a server component, those attributes are not included on the client component equivalent. You can use the clientAttribute
tag on the JSF page, and the value will then be available on both the server and client. For information about posting client values back to the server, see Section 5.4, "Sending Custom Events from the Client to the Server." For information about bonus attributes, see Section 3.7, "Using Bonus Attributes for Client-Side Components."The JavaScript method getSource()
returns the original source of a client event. For example, the File Explorer application contains the showAboutFileExplorerPopup
function shown in Example 5-6, that could be used by multiple events to set the alignment on a given popup dialog or window, using client attributes to pass in the values. Because each event that uses the function may have different values for the attributes, the function must know which source fired the event so that it can access the corresponding attribute values (for more about using client attributes, see Section 5.3.3, "How to Use Client-Side Attributes for an Event").
Example 5-6 Finding the Source Component of a Client Event
Explorer.showAboutFileExplorerPopup = function(event)
{
var source = event.getSource();
var alignType = source.getProperty("align");
var alignCompId = source.getProperty("alignId");
var popupCompId = source.getProperty("popupCompId");
source.show({align:alignType, alignId:alignCompId});
event.cancel();
}
The getSource()
method is called to determine the client component that fired the current focus event, which in this case is the popup component.
There may be cases when you want the script logic to cause some sort of change on a component. To do this, you may need attribute values passed in by the event. For example, the File Explorer application contains the showAboutFileExplorerPopup
function shown in Example 5-7, that can be used to set the alignment on a given popup component, using client attributes to pass in the values. The attribute values are accessed by calling the getProperty
method on the source component.
Example 5-7 Attribute Values Are Accessed from JavaScript
Explorer.showAboutFileExplorerPopup = function(event) { var source = event.getSource(); var alignType = source.getProperty("align"); var alignCompId = source.getProperty("alignId"); var popupCompId = source.getProperty("popupCompId"); var aboutPopup = event.getSource().findComponent(popupCompId); aboutPopup.show({align:alignType, alignId:alignCompId}); event.cancel(); }
The values are set on the source component, as shown in Example 5-8.
Example 5-8 Setting Attributes on a Component
<af:commandMenuItem id="aboutMenuItem" text="#{explorerBundle['menuitem.about']}" clientComponent="true"> <af:clientListener method="Explorer.showAboutFileExplorerPopup" type="action"/> <af:clientAttribute name="popupCompId" value=":aboutPopup"/> <af:clientAttribute name="align" value="end_after"/> <af:clientAttribute name="alignId" value="aboutMenuItem"/> </af:commandMenuItem>
Using attributes in this way allows you to reuse the script across different components, as long as they all trigger the same event.
There may be times when you do not want the user to be able to interact with the UI while a long-running event is processing. For example, suppose your application uses a button to submit an order, and part of the processing includes creating a charge to the user's account. If the user were to inadvertently press the button twice, the account would be charged twice. By blocking user interaction until server processing is complete, you ensure no erroneous client activity can take place.
The ADF Faces JavaScript API includes the AdfBaseEvent.preventUserInput
function. To prevent all user input while the event is processing, you can call the preventUserInput
function, and a glass pane will cover the entire browser window, preventing further input until the event has completed a roundtrip to the server.
You can use the preventUserInput
function only with custom events, events raised in a custom client script, or events raised in a custom client component's peer. Additionally, the event must propagate to the server. Example 5-9 shows how you can use preventUserInput
in your JavaScript.
function queueEvent(event) { event.cancel(); // cancel action event var source = event.getSource(); var params = {}; var type = "customListener"; var immediate = true; var isPartial = true; var customEvent = new AdfCustomEvent(source, type, params, immediate); customEvent.preventUserInput(); customEvent.queue(isPartial); }
By default, some client events propagate to the server once processing has completed on the client. In some circumstances, it is desirable to block this propagation. For instance, if you are using a commandButton
component to execute JavaScript code when the button is clicked, and there is no actionListener
event listener on the server, propagation of the event is a waste of resources. To block propagation to the server, you call the cancel()
function on the event in your listener. Once the cancel()
function has been called, the isCanceled()
function will return true
.
Example 5-10 shows the showAboutFileExplorerPopup
function, which cancels its propagation.
Example 5-10 Canceling a Client Event from Propagating to the Server
Explorer.showAboutFileExplorerPopup = function(event)
{
var source = event.getSource();
var alignType = source.getProperty("align");
var alignCompId = source.getProperty("alignId");
var popupCompId = source.getProperty("popupCompId");
var aboutPopup = event.getSource().findComponent(popupCompId);
aboutPopup.show({align:alignType, alignId:alignCompId});
event.cancel();
}
Canceling an event may also block some default processing. For example, canceling an AdfUIInputEvent
event for a context menu will block the browser from showing a context menu in response to that event.
The cancel()
function call will be ignored if the event cannot be canceled, which an event indicates by returning false
from the isCancelable()
function (events that cannot be canceled show "no" in the Is Cancelable column in Table 5-3). This generally means that the event is a notification that an outcome has already completed, and cannot be blocked. There is also no way to uncancel an event once it has been canceled.
Event processing in general is taken from the browser's native event loop. The page receives all DOM events that bubble up to the document, and hands them to the peer associated with that piece of DOM. The peer is responsible for creating a rich client JavaScript event object that wraps that DOM event, returning it to the page, which queues the event (for more information about peers and the ADF Faces architecture, see Chapter 3, "Using ADF Faces Architecture").
The event queue on the page most commonly empties at the end of the browser's event loop once each DOM event has been processed by the page (typically, resulting in a component event being queued). However, because it is possible for events to be queued independently of any user input (for example, poll components firing their poll event when a timer is invoked), queueing an event also starts a timer that will force the event queue to empty even if no user input occurs.
The event queue is a First-In-First-Out queue. For the event queue to empty, the page takes each event object and delivers it to a broadcast()
function on the event source. This loop continues until the queue is empty. It is completely legitimate (and common) for broadcasting an event to indirectly lead to queueing a new, derived event. That derived event will be broadcast in the same loop.
When an event is broadcast to a component, the component does the following:
Delivers the event to the peer's DispatchComponentEvent
method.
Delivers the event to any listeners registered for that event type.
Checks if the event should be bubbled, and if so initiates bubbling. Most events do bubble. Exceptions include property change events (which are not queued, and do not participate in this process at all) and, for efficiency, mouse move events.
While an event is bubbling, it is delivered to the AdfUIComponent
HandleBubbledEvent
function, which offers up the event to the peer's DispatchComponentEvent
function. Note that client event listeners do not receive the event, only the peers do.
Event bubbling can be blocked by calling an event's stopBubbling()
function, after which the isBubblingStopped()
function will return true
, and bubbling will not continue. As with cancelling, you cannot undo this call.
Note:
Canceling an event does not stop bubbling. If you want to both cancel an event and stop it from bubbling, you must call both functions.If none of the prior work has canceled the event, calls the AdfUIComponent.HandleEvent
method, which adds the event to the server event queue, if the event requests it.
Several components in ADF Faces are NamingContainer
components, such as pageTemplate
, subform
, table
, and tree
. When working with client-side API and events in pages that contain NamingContainer
components, you should use the findComponent()
method on the source component.
For example, because all components in any page within the File Explorer application eventually reside inside a pageTemplate
component, any JavaScript function must use the getSource()
and findComponent()
methods, as shown in Example 5-11. The getSource()
method accesses the AdfUIComponent
class, which can then be used to find the component.
Example 5-11 JavaScript Using the findComponent() Method
function showPopup(event) { event.cancel(); var source = event.getSource(); var popup = source.findComponent("popup"); popup.show({align:"after_end", alignId:"button"}); }
When you use the findComponent()
method, the search starts locally at the component where the method is invoked. For more information about working with naming containers, see Section 3.5, "Locating a Client Component on a Page."
While the clientAttribute
tag supports sending bonus attributes from the server to the client, those attributes are not synchronized back to the server. To send any custom data back to the server, use a custom event sent through the AdfCustomEvent
class and the serverListener
tag.
The AdfCustomEvent.queue()
JavaScript method enables you to fire a custom event from any component whose clientComponent
attribute is set to true
. The custom event object contains information about the client event source and a map of parameters to include on the event. The custom event can be set for immediate delivery (that is, during the Apply Request Values phase), or non-immediate delivery (that is, during the Invoke Application phase).
For example, in the File Explorer application, after entering a file name in the search field on the left, users can press the Enter key to invoke the search. As Example 5-12 shows, this happens because the inputText
field contains a clientListener
that invokes a JavaScript function when the Enter key is pressed.
Example 5-12 clientListener Invokes JavaScript Function and Causes ServerLIstener to Be Invoked
//Code on the JSF page... <af:inputText id="searchCriteriaName" value="#{explorer.navigatorManager.searchNavigator. searchCriteriaName}" shortDesc="#{explorerBundle['navigator.filenamesearch']}"> <af:serverListener type="enterPressedOnSearch" method="#{explorer.navigatorManager. searchNavigator.searchOnEnter}"/> <af:clientListener type="keyPress" method="Explorer.searchNameHandleKeyPress"/> </af:inputText> //Code in JavaScript file... Explorer.searchNameHandleKeyPress = function (event) { if (event.getKeyCode()==AdfKeyStroke.ENTER_KEY) { var source = event.getSource(); AdfCustomEvent.queue(source, "enterPressedOnSearch", {}, false); } }
The JavaScript contains the AdfCustomEvent.queue
method that takes the event source, the string enterPressedOnSearch
as the custom event type, a null parameter map, and False
for the immediate parameter.
The inputText
component on the page also contains the following serverListener
tag:
<af:serverListener type="enterPressedOnSearch"
method="#{explorer.navigatorManager.
searchNavigator.searchOnEnter}"/>
Because the type value enterPressedOnSearch
is the same as the value of the parameter in the AdfCustomEvent.queue
method in the JavaScript, the method that resolves to the method expression #{explorer.navigatorManager.searchNavigator.searchOnEnter}
will be invoked.
To send a custom event from the client to the server, fire the client event using a custom event type, write the server listener method on a backing bean, and have this method process the custom event. Next, register the server listener with the component.
Create the JavaScript that will handle the custom event using the AdfCustomEvent.queue()
method to provide the event source, custom event type, and the parameters to send to the server.
For example, the JavaScript used to cause the pressing of the Enter key to invoke the search functionality uses the AdfCustomEvent.queue
method that takes the event source, the string enterPressedOnSearch
as the custom event type, a null parameter map, and False
for the immediate parameter, as shown in Example 5-13.
Create the server listener method on a managed bean. This method must be public and take an oracle.adf.view.rich.render.ClientEvent
object and return a void
type. Example 5-14 shows the code used in the SearchNavigatorView
managed bean that simply calls another method to execute the search and then refreshes the navigator.
Example 5-14 Server Listener Method for a Custom Client Event
public void searchOnEnter(ClientEvent clientEvent) { doRealSearchForFileItem(); // refresh search navigator this.refresh(); }
Note:
The Java-to-JavaScript transformation can lose type information forNumbers
, chars
, Java Objects
, arrays
, and nonstring CharSequences
. Therefore, if an object being sent to the server was initially on the server, you may want to add logic to ensure the correct conversion. See Section 5.4.3, "What You May Need to Know About Marshalling and Unmarshalling Data."Register the clientListener
by dragging a Client Listener from the Operations panel of the Component Palette, and dropping it as a child to the component that raises the event.
Note:
On the component that will fire the custom client event, theclientComponent
attribute must be set to true
to ensure that a client-side generated component is available.In the Insert Client Listener dialog, enter the method and type for the JavaScript function. Be sure to include a library name if the script is not included on the page. The type can be any string used to identify the custom event, for example, enterPressedOnSearch
was used in the File Explorer.
Register the server listener by dragging a Server Listener from the Operations panel of the Component Palette, and dropping it as a sibling to the clientListener
tag.
In the Insert Server Listener dialog, enter the string used as the Type value for the client listener, as the value for this server listener, for example enterPressedOnSearch
.
In the Property Inspector, for the method
attribute, enter an expression that resolves to the method created in Step 2.
At runtime, when the user initiates the event, for example, pressing the Enter key, the client listener script executes. This script calls the AdfCustomEvent.queue()
method, and a custom event of the specified event type is queued on the input component. The server listener registered on the input component receives the custom event, and the associated bean method executes.
Marshalling and unmarshalling is the process of converting data objects of a programming language into a byte stream and back into data objects that are native to the same or a different programming language. In ADF Faces, marshalling and unmarshalling refer to transformation of data into a suitable format so that it can be optimally exchanged between JavaScript on the client end and Java on the server end. When the client is browser-based, the two common strategies for marshalling are JavaScript Object Notation (JSON) and XML. ADF Faces uses a mix of both of these strategies, with the information sent from the server to the client mostly as JSON and information sent from the client to the server as XML (for more information about JSON, see http://www.json.org
).
When you send information from JavaScript to Java, the JavaScript data objects are converted (marshalled) into XML, which is then parsed back or unmarshalled into Java objects at the server-side. For example, consider a JSF page that has a commandButton
component whose ID is cmd
. When a user clicks the commandButton
component, the client must communicate to the server that an actionEvent
has been fired by this specific commandButton
. In the requestParameter
map, the information is mapped with the key using the format event + . + id
where id
is the ID of the component. So the requestParameter
map key for the commandComponent
would be the XML string stored as the value of the key event.cmd
.
The XML fragment after marshalling in this example would be:
<m xmlns="http:/oracle.com/richClient/comm"><k v="type"><s>action</s></k></m>
The m
in the example means that this should be unmarshalled into a map. The k
denotes the key and the value is of type String
. On the server side, this XML fragment is parsed into a java.util.Map
of one entry having type
(java.lang.String
) as the key and action
(java.lang.String
) as the value.
The unmarshalled information is grouped per client ID, stored in the request map, and used when the components are being decoded. So in this example, when the commandButton
is decoded, it will check for the presence of any client events using its client ID (event.cmd
) and then queue an action event if one is found (the decode behavior is implemented in the renderer hierarchy for commandButton
component).
Table 5-5 shows the mapping between corresponding JavaScript and Java types.
Table 5-5 JavaScript to Java Type Map
JavaScript Type | Java Type |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Marshalling from Java to JavaScript happens mostly through JSON. This type of marshalling is straightforward as JSON is the object literal notation in JavaScript. The client-components usually have their properties encoded in JSON. Consider the following example:
new AdfRichCommandButton('demoTemplate:richComand' {'partialSubmit':true,'useWindow':false})
The second argument ({'partialSubmit':true,'useWindow':false}) is a JSON object. There is no additional unmarshalling step required at the browser end as JSON can directly be parsed into the JavaScript environment as an object.
Encoding for a table also uses JSON to pass push messages to the client. The following is an example of an envelope containing a single encoded push message:
[{'rKey':'0','type':'update','data':[{'val':'Active Data Every Second: on row 0:78','prop':'value','cInd':0},{'val':'Active Data Every Second: on row 0:78','prop':'value','cInd':1}]}]
The envelope is a JavaScript Array
with only one object, which describes the message. This message contains information about the type of change, the actual value of the data, and so on, that is then used by the client-side table peer to update the table itself.
Table 5-6 shows the mapping between corresponding Java and JavaScript types.
Table 5-6 Java to JavaScript Type Map
Java Type | JavaScript Type |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Note that there could be some loss of information during the conversion process. For example, say you are using the following custom event to send the number 1
and the String test
, as shown in the following example:
AdfCustomEvent.queue(event.getSource(), "something", {first:1, second:"test"});
In the server-side listener, the type of the first
parameter would become a java.lang.Double
because numbers are converted to Doubles
when going from JavaScript to Java. However, it might be that the parameter started on the server side as an int
, and was converted to a number when conversion from Java to JavaScript took place. Now on its return trip to the server, it will be converted to a Double
.
Using the ExtendedRenderKitService
class, you can add JavaScript to an event response, for example, after invoking an action method binding. It can be a simple message like sending an alert informing the user that the database connection could not be established, or a call to a function like hide()
on a popup window to programatically dismiss a popup dialog.
For example, in the File Explorer application, when the user clicks the UpOneFolder
navigation button to move up in the folder structure, the folder pane is repainted to display the parent folder as selected. The HandleUpOneFolder()
method is called in response to clicking the UpOneFolder
button event. It uses the ExtendedRenderKitService
class to add JavaScript to the response.
Example 5-15 shows the UpOneFolder
code in the page with the actionListener
attribute bound to the HandleUpOneFolder()
handler method which will process the action event when the button is clicked.
Example 5-15 Invoking a Method to Add JavaScript to a Response
<af:commandToolbarButton id="upOneFolder"
. . .
actionListener="#{explorer.headerManager.handleUpOneFolder}"/>
Example 5-16 shows the handleUpOneFolder
method that uses the ExtendedRenderKitService
class.
Example 5-16 Adding JavaScript to a Response
public void handleUpOneFolder(ActionEvent actionEvent) { UIXTree folderTree = feBean.getNavigatorManager().getFoldersNavigator().getFoldersTreeComponent(); Object selectedPath = feBean.getNavigatorManager().getFoldersNavigator().getFirstSelectedTreePath(); if (selectedPath != null) { TreeModel model = _feBean.getNavigatorManager().getFoldersNavigator().getFoldersTreeModel(); Object oldRowKey = model.getRowKey(); try { model.setRowKey(selectedPath); Object parentRowKey = model.getContainerRowKey(); if (parentRowKey != null) { folderTree.getSelectedRowKeys().clear(); folderTree.getSelectedRowKeys().add(parentRowKey); // This is an example of how to force a single attribute // to rerender. The method assumes that the client has an optimized // setter for "selectedRowKeys" of tree. FacesContext context = FacesContext.getCurrentInstance(); ExtendedRenderKitService erks = Service.getRenderKitService(context, ExtendedRenderKitService.class); String clientRowKey = folderTree.getClientRowKeyManager(). getClientRowKey(context, folderTree, parentRowKey); String clientId = folderTree.getClientId(context); StringBuilder builder = new StringBuilder(); builder.append("AdfPage.PAGE.findComponent('"); builder.append(clientId); builder.append("').setSelectedRowKeys({'"); builder.append(clientRowKey); builder.append("':true});"); erks.addScript(context, builder.toString()); } } finally { model.setRowKey(oldRowKey); } // Only really needed if using server-side rerendering // of the tree selection, but performing it here saves // a roundtrip (just one, to fetch the table data, instead // of one to process the selection event only after which // the table data gets fetched!) _feBean.getNavigatorManager().getFoldersNavigator().openSelectedFolder(); } }
ADF Faces client behavior tags provide declarative solutions to common client operations that you would otherwise have to write yourself using JavaScript, and register on components as client listeners. By using these tags instead of writing your own JavaScript code to implement the same operations, you reduce the amount of JavaScript code that needs to be downloaded to the browser.
ADF Faces provides these client behavior tags that you can use in place of client listeners:
panelDashboardBehavior
: Enables the runtime insertion of a child component into a panelDasboard
component to appear more responsive. For details, see Section 8.7.1, "How to Use the panelDashboard Component."
insertTextBehavior
: Enables a command component to insert text at the cursor in an inputText
component. For details, see Section 9.3.2, "How to Add the Ability to Insert Text into an inputText Component."
richTextEditorInsertBehavior
: Enables a command component to insert text (including preformatted text) at the cursor in a richTextEditor
component. For details, see Section 9.8.2, "How to Add the Ability to Insert Text into a richTextEditor Component."
showPopupBehavior
: Enables a command component to launch a popup component. For details, see Section 13.4, "Invoking Popup Elements."
showPrintablePageBehavior
: Enables a command component to generate and display a printable version of the page. For details, see Section 33.2, "Displaying a Page for Print."
scrollComponentIntoViewBehavior
: Enables a command component to jump to a named component when clicked. For details, see Section 5.6.1, "How to Use the scrollComponentIntoViewBehavior Tag."
Client behavior tags cancel server-side event delivery automatically. Therefore, any actionListener
or action
attributes on the parent component will be ignored. This cannot be disabled. If you want to also trigger server-side functionality, you should use either a client-side event (see Section 5.3, "Using JavaScript for ADF Faces Client Events"), or add an additional client listener that uses AdfCustomEvent
and af:serverListener
to deliver a server-side event (see Section 5.4, "Sending Custom Events from the Client to the Server").
Use the scrollComponentIntoViewBehavior
tag when you want the user to be able to jump to a particular component on a page. This action is similar to an anchor in HTML. For example, you may want to allow users to jump to a particular part of a page using a commandLink
component. For the richTextEditor
and inlineFrame
components, you can jump to a subcomponent. For example, Figure 5-1 shows a richTextEditor
component with a number of sections in its text. The command links below the editor allow the user to jump to specific parts of the text.
You can also configure the tag to have focus switched to the component to which the user has scrolled.
To use the scrollComponentIntoViewBehavior tag:
Create a command component that the user will click to jump to the named component. For procedures, see Section 18.2.1, "How to Use Command Buttons and Command Links."
In the Component Palette, from the Operations section, drag and drop a Scroll Component Into View Behavior as a child to the command component.
In the Insert Scroll Component Into View Behavior dialog, use the dropdown arrow to select Edit and then navigate to select the component to which the user should jump.
In the Property Inspector, set the focus
attribute to true
if you want the component to have focus after the jump.
For a richTextEditor
or inlineFrame
component, optionally enter a value for the subTargetId
attribute. This ID is defined in the value of the richTextEditor
or inlineFrame
component.
For example, the value of the subTargetId
attribute for the scrollComponentIntoViewBehavior
tag shown in Figure 5-1 is Introduction
. The value of the richTextEditor
is bound to the property shown in Example 5-17. Note that Introduction
is the ID for the first header.
Example 5-17 subTargetId Value Defined in a Property
private static final String _RICH_SECTIONED_VALUE = "<div>\n" + " <h2>\n" + " <a id=\"Introduction\"></a>Introduction</h2>\n" + " <p>\n" + " The ADF Table component is used to display a list of structured data. For example,\n" + " if we have a data structure called Person that has two properties - firstname and\n" + " lastname, we could use a Table with two columns - one for firstname, and the other\n" + " for lastname - to display a list of Person objects.\n" + " </p>\n" + " </div>\n" + " <div>\n" + " <h2>\n" + " <a id=\"The_Table_Model\"></a>The Table Model</h2>\n" + " <p>\n" + . . . </div>";
ADF Faces provides the poll component whose pollEvent
can be used to communicate with the server at specified intervals. For example, you might use the poll component to update an outputText
component, or to deliver a heartbeat to the server to prevent a user from being timed out of their session.
You need to create a listener for the pollEvent
that will be used to do the processing required at poll time. For example, if you want to use the poll component to update the value of an outputText
component, you would implement a pollEventListener
method that would check the value in the data source and then update the component.
You can configure the interval time to determine how often the poll component will deliver its poll event. You also configure the amount of time after which the page will be allowed to time out. This can be useful, as the polling on a page causes the session to never time out. Each time a request is sent to the server, a session time out value is written to the page to determine when to cause a session time out. Because the poll component will continually send a request to the server (based on the interval time), the session will never time out. This is expensive both in network usage and in memory.
To avoid this issue, the web.xml
configuration file contains the oracle.adf.view.rich.poll.TIMEOUT
context-parameter, which specifies how long a page should run before it times out. A page is considered eligible to time out if there is no keyboard or mouse activity. The default timeout period is set at ten minutes. So if user is inactive for 10 minutes, that is, does not use the keyboard or mouse, then the framework stops polling, and from that point on, the page participates in the standard server-side session timeout (for more information, see Section A.2.3.20, "Session Timeout Warning").
If the application does time out, when the user moves the mouse or uses the keyboard again, a new session timeout value is written to the page, and polling starts again.
You can override this time for a specific page using the poll component's timeout
attribute.
When you use the poll component, you normally also create a handler method to handle the functionality for the polling event.
It may be helpful to have an understanding of how the attributes can affect functionality. For more information, see Section 5.7, "Using Polling Events to Update Pages"
In a managed bean, create a handler for the poll event. For more information about managed beans, see Section 2.6, "Creating and Using Managed Beans"
Create a poll component by dragging and dropping a Poll from the Operations panel of the Component Palette.
In the Property Inspector, expand the Common section and set the following:
Interval: Enter the amount of time in milliseconds between poll events. Set to 0 to disable polling.
PollListener: Enter an EL expression that evaluates to the method in Step 1.
If you want to override the global timeout value in the web.xml
file, expand the Other section and set Timeout to the amount of time in milliseconds after which the page will stop polling and the session will time out.