6 Handling Events

This chapter describes how to handle events on the server as well as on the client.

This chapter includes the following sections:

About Events and Event Handling

ADF Faces supports server-side action and value change events and can also invoke client-side action and value change events. ADF Faces provides a list of event types and event root components.

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 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 corresponding 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 the form 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

Events and Partial Page Rendering

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 and the lifecycle is run only on that portion.

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 information about this aspect of the lifecycle, see 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 rerenderd, and not the whole page. Another example is the panelCollection component that surrounds a table and provides among other things, a toolbar. Action events triggered by a button on the toolbar will cause the lifecycle to be run only on the child components of the panelCollection component.

The following components are considered event root components:

  • popup

  • region

  • panelCollection

  • calendar

  • editableValueHolder components (such as inputText)

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 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. For information about components and their associated events, see Event and Even Root Components.

Tip:

If components outside of the event root need to be processed when the event root is processed, then you can programmatically determine which components should participate, and whether they should be executed in the lifecycle or simply rendered. See Rerendering Partial Page Content.

Event and Even Root Components

Table 6-1 shows the all event types in ADF Faces, and whether or not the source component is an event root.

Table 6-1 Events and Event Root Components

Event Type Component Trigger Is Event Root

action

All command components

false

dialog

dialog

false

disclosure

showDetail, showDetailHeader

true

disclosure

showDetailItem

true

focus

tree, treeTable

true

launch

All command components

NA

launchPopup

inputListOfValues, inputComboboxListOfValues

true

load

document

NA

poll

poll

true

popupOpened

popup

NA

popupOpening

popup

NA

popupClosed

popup

NA

propertyChange

All components

NA

queryEvent

query, quickQuery

true

queryOperation

query, quickQuery

true

rangeChange

table

NA

regionNavigation

region

NA

return

All command components

true

returnPopupData

inputListOfValues, inputComboboxListOfValues

true

returnPopup

inputListOfValues, inputComboboxListOfValues

true

rowDisclosure

tree, treeTable, treemap, sunburst

true

sort

treeTable, table

true

valueChange

All input and select components (components that implement EditableValueHolder)

true

Client-Side Event Model

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 ADF Faces framework 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.

Using ADF Faces Server Events

ADF Faces supports server-side action and value change events. To process the events, you must understand the different server-side event types available and the components that trigger these events.

ADF Faces provides a number of server-side events. Table 6-2 lists the events generated by ADF Faces components on the server, and the components that trigger them.

Table 6-2 ADF Faces Server Events

Event Triggered by Component...

ActionEvent

All command components. See Working with Navigation Components.

ActiveDataEvent

Used to update components based on events. See Using the Active Data Service inDeveloping Fusion Web Applications with Oracle Application Development Framework.

AttributeChangeEvent

All input and select components (components that implement EditableValueHolder). See Using Input Components and Defining Forms .

CalendarActivity DurationChangeEvent

CalendarActivityEvent

CalendarDisplay ChangeEvent

CalendarEvent

The Calendar component. See Using a Calendar Component .

CarouselSpinEvent

The carousel component. See Displaying Images in a Carousel.

ColumnSelectionEvent

ColumnVisibility ChangeEvent

The table and treeTable components. See Using Tables, Trees, and Other Collection-Based Components.

ContextInfoEvent

The contextInfo component. See Displaying Contextual Information in Popups.

DialogEvent

The dialog component. See Using Popup Dialogs, Menus, and Windows.

DisclosureEvent

The showDetail, showDetailHeader, showDetailItem components. See Displaying and Hiding Contents Dynamically and Displaying or Hiding Contents in Panels.

DropEvent

Components that support drag and drop. See Adding Drag and Drop Functionality.

FocusEvent *

The tree and treeTable components. See Using Tables, Trees, and Other Collection-Based Components.

ItemEvent

The panelTabbed component. See Displaying or Hiding Contents in Panels. Also, the navigationPane component. See Using Navigation Items for a Page Hierarchy.

LaunchEvent

All command components. See Working with Navigation Components.

LaunchPopupEvent

The inputListOfValues and inputComboboxListOfValues components. See Using Query Components.

LoadEvent **

The document component. See How to Configure the document Tag.

PollEvent

The poll component. See Using Polling Events to Update Pages

PopupCanceledEvent

PopupFetchEvent

The popup component. See Using Popup Dialogs, Menus, and Windows.

QueryEvent

QueryOperationEvent

The query and quickQuery components. See Using Query Components.

RangeChangeEvent

The table component. See Using Tables, Trees, and Other Collection-Based Components.

RegionNavigationEvent

The region component. See Using Task Flows as Regions in Developing Fusion Web Applications with Oracle Application Development Framework.

ReturnEvent

All command components. See Working with Navigation Components.

ReturnPopupEvent

The inputListOfValues and inputComboboxListOfValues components. See Using Query Components.

ReturnPopupDataEvent

The popup component. See Using Popup Dialogs, Menus, and Windows.

RowDisclosureEvent

The tree and treeTable components, as well as the treemap and sunburst DVT components. See Using Tables, Trees, and Other Collection-Based Components and Using Treemap and Sunburst Components .

SelectionEvent

The table, tree, and treeTable components, as well as the treemap and sunburst DVT components. See Using Tables, Trees, and Other Collection-Based Components and Using Treemap and Sunburst Components .

SortEvent

The table and treeTable components. See Using Tables, Trees, and Other Collection-Based Components.

ValueChangeEvent

All input and select components (components that implement EditableValueHolder). See Using Input Components and Defining Forms .

WindowLifecycleEvent

Delivered when the LifecycleState of a window changes. See the Java API Reference for Oracle ADF Faces.

WindowLifecycle NavigateEvent

Delivered when the current window is unloaded in order to navigate to a new location. See the Java API Reference for Oracle ADF Faces.

* 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).

How to Handle Server-Side Events

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.

Before you begin:

It may be helpful to have an understanding of server-side events. See Using ADF Faces Server Events.

To handle server-side events:

  1. 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. The following example shows the code for the tableSelectFileItem handler. (For information about creating and using managed beans, see Creating and Using Managed Beans.)
      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 a processEvent() 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
    }
  2. To register an event listener method on a component, in the Structure window, select the component that will invoke the event. In the Properties window, use the dropdown menu next to the event listener property, and choose Edit.
  3. Use the Edit Property dialog to select the managed bean and method created in Step 1.

    The following example shows sample code for registering a selection event listener method on a table component.

    <af:table id="folderTable" var="file"
    . . . 
              rowSelection="single"
              selectionListener="#{explorer.tableContentView.tableSelectFileItem}"
    . . .
    </af:table>

Using JavaScript for ADF Faces Client Events

ADF Faces can invoke client-side action and value change events. To process client-side events, you must understand the different event types available and also the components that trigger these events. To use client-side events, you need to first create the JavaScript that will handle the event.

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. See How to Prevent Events from Propagating to the Server.

Best Practice:

Keyboard and mouse events wrap native DOM events using the AdfUIInputEvent 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. The following shows an example of a JavaScript function associated with an action event.

<af:button id="button0"
                  text="Do something in response to an action">
  <af:clientListener method="someJSMethod" type="action"/>
</af:button>

Tip:

Use the clientListener tag instead of the component's JavaScript event properties.

All ADF Faces components support the JSF 2.0 client behavior API. Client events on ADF Faces components are also exposed as client behaviors. Client behaviors tags (like f:ajax) allow you to declaratively attach JavaScript to a component, which will then execute in response to a client behavior. For example, the following code shows the f:ajax tag attached to an inputText component. This tag will cause the outputText component to render when the change client event occurs on the inputText component.

af:inputText ...>
  <f:ajax name="change" render="ot1" execute="@this" />
</af:inputText>
<af:outputText id="ot1" ... />

ADF Faces Client-Side Events

Table 6-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 6-3 ADF Faces Client Events

Event Class Event Type Propagates to Server Can Be Canceled Triggered by Component

AdfActionEvent

action

Yes

Yes

All command components

AdfBusyStateEvent

busyState

No

No

Triggered by the page

AdfCarouselSpinEvent

event

Yes

No

carousel

AdfChooseDateLoadEvent

load

No

Yes

chooseDate

AdfColumnSelectionEvent

event

Yes

Yes

table, treeTable

AdfComponentEvent

load

Yes

Yes

document

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.

AdfComponentFocusEvent

No

Yes

Any component that can receive focus

AdfDateSelectionEvent

dateSelection

No

Yes

chooseDate

AdfDialogEvent

event

Yes

Yes

dialog

When user selects the OK or Cancel button in a dialog

AdfDisclosureEvent

event

Yes

Yes

panelBox, region, showDetail, showDetailHeader, showDetailItem

When the disclosure state is toggled by the user

AdfDomComponentEvent

inlineFrameLoad

Yes

Yes

inlineFrame

When the internal iframe fires its load event.

AdfDropEvent

drop

Yes

No

Any component that supports drag and drop

AdfFocusEvent

focus

Yes

Yes

tree, treeTable

AdfItemEvent

item

Yes

Yes

commandNavigationItemshowDetailItem

AdfLaunchPopupEvent

launch

Yes

Yes

inputListOfValues, inputComboboxListOfValues

AdfPollEvent

poll

Yes

Yes

poll

AdfPopupCanceledEvent

popupCanceled

Yes

Yes

popup

After a popup is unexpectedly closed or the cancel method is invoked

AdfPopupClosedEvent

popupClosed

No

No

popup

After a popup window or dialog is closed

AdfPopupOpenedEvent

popupOpened

No

No

popup

After a popup window or dialog is opened

AdfPopupOpeningEvent

popupOpening

No

Yes

popup

Prior to opening a popup window or dialog

AdfPropertyChangeEvent

propertyChange

No

No

All components

AdfQueryEvent

event

Yes

Yes

query, quickQuery

Upon a query action (that is, when the user clicks the search icon or search button)

AdfQueryOperationEvent

event

Yes

Yes

query, quickQuery

AdfReturnEvent

returnEvent

Yes

Yes

All command components

AdfReturnPopupDataEvent

launchEvent

Yes

Yes

inputListOfValues, inputComboboxListOfValues

AdfReturnPopupEvent

returnPopup

Yes

Yes

inputListOfValues, inputComboboxListOfValues

AdfRowDisclosureEvent

rowDisclosure

Yes

Yes

tree, treeTable

When the row disclosure state is toggled

AdfRowKeySetChangeEvent

selection, rowDisclosure

Always for disclosure event on a table. Yes, if there is a selection listener or a disclosure listener on the server.

Yes

table, treeTable, tree

AdfSelectionEvent

selection

Yes

Yes

tree, treeTable, table

When the selection state changes

AdfSortEvent

sort

Yes

Yes

treeTable, table

When the user sorts the table data

AdfValueChangeEvent

valueChange

Yes

Yes

All input and select components (components that implement EditableValueHolder)

When the value of an input or select component is changed

ADF Faces also supports client keyboard and mouse events, as shown in Table 6-4.

Table 6-4 Keyboard and Mouse Event Types Supported

Event Type Event Fires When...

click

User clicks a component

dblclick

User double-clicks a component

mousedown

User moves mouse down on a component

mouseup

User moves mouse up on a component

mousemove

User moves mouse while over a component

mouseover

Mouse enters a component

mouseout

Mouse leaves a component

keydown

User presses key down while focused on a component

keyup

User releases key while focused on a component

keypress

When a successful keypress occurs while focused on a component

focus

Component gains keyboard focus

blur

Component loses keyboard focus

How to Use Client-Side Events

To use client-side events, you need to first create the JavaScript that will handle the event. You then use a clientListener tag.

Before you begin:

It may be helpful to have an understanding of client-side events. See Using JavaScript for ADF Faces Client Events.

To use client-side events:

  1. Create the JavaScript event handler function. For information about creating JavaScript, see 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 information about locating client components, see 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. See 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. See 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 6-3. If you do not need this extra processing, then you can cancel that propagation. See How to Prevent Events from Propagating to the Server.

  2. 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 as f:ajax) to respond to the client event, as all client events on ADF Faces components are also exposed as client behaviors. See the Java EE 6 tutorial (http://download.oracle.com/javaee/index.html)

    1. Select the component to invoke the JavaScript, and in the Properties window, set ClientComponent to true.

    2. In the Components window, from the Operations panel, in the Listeners group, drag a Client Listener and drop it as a child to the selected component.

    3. 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 6-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 6-4 lists the keyboard and mouse event types.

      The following example shows the code used to invoke the showHelpFileExplorerPopup function from the Explorer.js JavaScript file.

      <af:commandMenuItem id="feedbackMenuItem"
                          text="#{explorerBundle['menuitem.feedback']}"
                          clientComponent="true">
        <af:clientListener method="Explorer.showHelpFileExplorerPopup"
                           type="action"/>
      </af:commandMenuItem>
      
    4. To add any attributes required by the function, in the Components window, from the Operations panel, drag a Client Attribute and drop it as a child to the selected component. Enter the name and value for the attribute in the Properties window. The following example 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>

    Best Practice:

    Keyboard and mouse events wrap native DOM events using the AdfUIInputEvent 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.

How to Return the Original Source of the Event

The JavaScript method getSource() returns the original source of a client event. For example, the File Explorer application contains the showAboutFileExplorerPopup function shown in the following example, 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 How to Use Client-Side Attributes for an 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.

How to Use Client-Side Attributes for an Event

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 the following example, 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.

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 the following example.

<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.

How to Block UI Input During Event Execution

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. The following example 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);
}   

How to Prevent Events from Propagating to the Server

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 button 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.

The following example shows the showAboutFileExplorerPopup function, which cancels its propagation.

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 6-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.

How to Indicate No Response is Expected

There may be times when you do not expect the framework to handle the response for an event. For example, when exporting table content to a spreadsheet, you don't need to wait for r the call to return To let the framework know that no response is expected, you use the AdfBaseEvent.noResponseExpected() method.

What Happens at Runtime: How Client-Side Events Work

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 JavaScript event object that wraps that DOM event, returning it to the page, which queues the event (for information about peers and the ADF Faces architecture, see Using ADF Faces Client-Side 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:

  1. Delivers the event to the peer's DispatchComponentEvent method.

  2. Delivers the event to any listeners registered for that event type.

  3. 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.

  4. 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.

What You May Need to Know About Using Naming Containers

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 the following example. The getSource() method accesses the AdfUIComponent class, which can then be used to find the component.

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 information about working with naming containers, see Locating a Client Component on a Page.

Sending Custom Events from the Client to the Server

In ADF Faces, you can use a custom event to send any custom data back to the server from the client. 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, and then register the server listener with the component.

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 the following example shows, this happens because the inputText field contains a clientListener that invokes a JavaScript function when the Enter key is pressed.

//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.

How to Send Custom Events from the Client to the Server

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.

Before you begin:

It may be helpful to have an understanding of sending custom events to the server. See Sending Custom Events from the Client to the Server.

To send custom events:

  1. 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 he following example.

    Explorer.searchNameHandleKeyPress = function (event)
    {
      if (event.getKeyCode()==AdfKeyStroke.ENTER_KEY)
      {
        var source = event.getSource();
        AdfCustomEvent.queue(source,
                             "enterPressedOnSearch", 
                             {}, 
                             false);
      } 
    }
    
  2. 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. The following example shows the code used in the SearchNavigatorView managed bean that simply calls another method to execute the search and then refreshes the navigator.
      public void searchOnEnter(ClientEvent clientEvent)
      {
        doRealSearchForFileItem();
        
        // refresh search navigator
        this.refresh();
      }
    

    Note:

    The Java-to-JavaScript transformation can lose type information for Numbers, 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 What You May Need to Know About Marshalling and Unmarshalling Data.

  3. To register the clientListener, in the Components window, from the Operations panel, drag a Client Listener and drop it as a child to the component that raises the event.

    Note:

    On the component that will fire the custom client event, the clientComponent attribute must be set to true to ensure that a client-side generated component is available.

  4. 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.
  5. To register the server listener, in the Components window, from the Operations panel, drag a Server Listener and drop it as a sibling to the clientListener tag.
  6. 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 Properties window, for the method attribute, enter an expression that resolves to the method created in Step 2.

What Happens at Runtime: How Client and Server Listeners Work Together

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.

What You May Need to Know About Marshalling and Unmarshalling Data

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.

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.

Mapping Java to JavaScript provides mapping between Java and JavaScript types.

Mapping Java to JavaScript

Table 6-5 shows how JavaScript types are mapped to the corresponding Java types in ADF Faces.

Table 6-5 JavaScript to Java Type Map

JavaScript Type Java Type

Boolean

java.lang.Boolean

Number

java.lang.Double

String

java.lang.String

Date

java.util.Date

Array

java.util.ArrayList

Object

java.util.Map

Table 6-6 shows how Java types map back to JavaScript types.

Table 6-6 Java to JavaScript Type Map

Java Type JavaScript Type

java.lang.Boolean

Boolean

java.lang.Double

Number

java.lang.Integer

Number

java.lang.Float

Number

java.lang.Long

Number

java.lang.Short

Number

java.lang.Character

String

java.lang.CharSequence

String

java.util.Collection

Array

java.util.Date

Date

java.util.Map

Object

Array

Array

java.awt.Color

TrColor

Executing a Script Within an Event Response

Executing JavaScript within an event response is useful when you have a JavaScript library that does certain operations on the client side, and you want to call these functions after finishing an action on the server side.

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.

The following example 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.

<af:btton id="upOneFolder"
. . .
        actionListener="#{explorer.headerManager.handleUpOneFolder}"/>

The following example shows the handleUpOneFolder method that uses the ExtendedRenderKitService class.

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();
    } 
    
  }

Using ADF Faces Client Behavior Tags

Client behavior tags in ADF Faces execute on the client side. ADF Faces provides a list of client behavior tags that you can use in place of client listeners.

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:

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 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 Sending Custom Events from the Client to the Server).

How to Use the scrollComponentIntoViewBehavior Tag

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 6-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.

Figure 6-1 scrollComponentIntoViewBehavior Tag in an Editor

This image is described in the surrounding text

You can also configure the tag to have focus switched to the component to which the user has scrolled.

Before you begin:

It may be helpful to have an understanding of behavior tags. See Using ADF Faces Client Behavior Tags.

To use the scrollComponentIntoViewBehavior tag:

  1. Create a command component that the user will click to jump to the named component. For procedures, see How to Use Buttons and Links for Navigation and Deliver ActionEvents.
  2. In the Components window, from the Operations panel, drag and drop a Scroll Component Into View Behavior as a child to the command component.
  3. 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.
  4. In the Properties window, set the focus attribute to true if you want the component to have focus after the jump.
  5. 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 6-1 is Introduction. The value of the richTextEditor is bound to the property shown in the following example. Note that Introduction is the ID for the first header.

    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>";

Using Polling Events to Update Pages

The ADF Faces poll component can be used to deliver poll events to the server as a means to periodically update page components. To use the poll component, you must create a handler method to handle the functionality for the polling event.

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 users 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 (see 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.

How to Use the Poll Component

When you use the poll component, you normally also create a handler method to handle the functionality for the polling event.

Before you begin:

It may be helpful to have an understanding of how the attributes can affect functionality. See Using Polling Events to Update Pages.

To use a poll component:

  1. In a managed bean, create a handler for the poll event. For information about managed beans, see Creating and Using Managed Beans.
  2. In the Components window, from the Operations panel, drag and drop a Poll onto the page.
  3. In the Properties window, 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.

    • Timeout: If you want to override the global timeout value in the web.xml file, set Timeout to the amount of time in milliseconds after which the page will stop polling and the session will time out.